Gids voor I / O in Groovy

1. Inleiding

Hoewel we in Groovy net als in Java met I / O kunnen werken, Groovy breidt de I / O-functionaliteit van Java uit met een aantal hulpmethoden.

In deze tutorial kijken we naar het lezen en schrijven van bestanden, het doorlopen van bestandssystemen en het serialiseren van gegevens en objecten via Groovy's het dossier uitbreidingsmethoden.

Waar van toepassing, zullen we linken naar onze relevante Java-artikelen voor eenvoudige vergelijking met het Java-equivalent.

2. Bestanden lezen

Groovy voegt handige functionaliteit toe voor het lezen van bestanden in de vorm van de elke regel methoden, methoden om BufferedReaders en InputStreams, en manieren om alle bestandsgegevens op te halen met één regel code.

Java 7 en Java 8 hebben vergelijkbare ondersteuning voor het lezen van bestanden in Java.

2.1. Lezen met elke regel

Bij tekstbestanden moeten we vaak elke regel lezen en verwerken. Groovy biedt een handige uitbreiding op java.io.File met de elke regel methode:

def lines = [] nieuw bestand ('src / main / resources / ioInput.txt'). eachLine {line -> lines.add (line)}

De sluiting voorzien elke regel heeft ook een handig optioneel regelnummer. Laten we het regelnummer gebruiken om alleen specifieke regels uit een bestand te halen:

def lineNoRange = 2..4 def lines = [] nieuw bestand ('src / main / resources / ioInput.txt'). eachLine {line, lineNo -> if (lineNoRange.contains (lineNo)) {lines.add (regel )}}

Standaard begint de regelnummering bij één. We kunnen een waarde opgeven om te gebruiken als het eerste regelnummer door deze als eerste parameter door te geven aan de elke regel methode.

Laten we onze regelnummers bij nul beginnen:

nieuw bestand ('src / main / resources / ioInput.txt'). eachLine (0, {line, lineNo -> if (lineNoRange.contains (lineNo)) {lines.add (line)}})

Als er een uitzondering wordt gegooid elke regel, Groovy zorgt ervoor dat de bestandsresource wordt gesloten. Net als een probeer-met-middelen of een probeer het eindelijk in Java.

2.2. Lezen met Reader

We kunnen ook gemakkelijk een BufferedReader van een Groovy het dossier voorwerp. We kunnen gebruiken withReader om een BufferedReader naar het bestandsobject en geef het door aan een afsluiting:

def actualCount = 0 nieuw bestand ('src / main / resources / ioInput.txt'). withReader {reader -> while (reader.readLine ()) {actualCount ++}}

Net als bij elke regel, de withReader methode zal de bron automatisch sluiten wanneer er een uitzondering wordt gegenereerd.

Soms willen we misschien de BufferedReader object beschikbaar. We zouden bijvoorbeeld van plan kunnen zijn om een ​​methode aan te roepen die er een als parameter gebruikt. We kunnen de newReader methode hiervoor:

def outputPath = 'src / main / resources / ioOut.txt' def reader = nieuw bestand ('src / main / resources / ioInput.txt'). newReader () nieuw bestand (outputPath) .append (reader) reader.close ( )

In tegenstelling tot de andere methoden die we tot nu toe hebben bekeken, wij zijn verantwoordelijk voor het sluiten van het BufferedReader resource wanneer we een GebufferdLezer op deze manier.

2.3. Lezen met InputStreams

Gelijkwaardig aan withReader en newReader, Groovy biedt ook methoden om gemakkelijk mee te werken InputStreams. Hoewel we tekst kunnen lezen met InputStreams en Groovy voegen er zelfs functionaliteit voor toe, InputStreams worden het meest gebruikt voor binaire gegevens.

Laten we gebruiken withInputStream om een InputStream tot een afsluiting en lees in de bytes:

byte [] data = [] nieuw bestand ("src / main / resources / binaryExample.jpg"). withInputStream {stream -> data = stream.getBytes ()}

Als we de InputStream object, we kunnen er een krijgen met behulp van newInputStream:

def outputPath = 'src / main / resources / binaryOut.jpg' def is = nieuw bestand ('src / main / resources / binaryExample.jpg'). newInputStream () nieuw bestand (outputPath) .append (is) is.close ( )

Net als bij de BufferedReader, we moeten onze InputStream middelen onszelf als we gebruiken newInputStream, maar niet bij gebruik withInputStream.

2.4. Andere manieren lezen

Laten we het onderwerp lezen afmaken door te kijken naar een paar methoden die Groovy heeft om alle bestandsgegevens in één instructie te verzamelen.

Als we de regels van ons bestand in een Lijst, we kunnen gebruiken verzamelen met een iterator het doorgegeven aan de sluiting:

def actualList = nieuw bestand ('src / main / resources / ioInput.txt'). collect {it}

Om de regels van ons bestand in een reeks Snaren, we kunnen gebruiken als String []:

def actualArray = nieuw bestand ('src / main / resources / ioInput.txt') als String []

Voor korte bestanden kunnen we de volledige inhoud in een Draad gebruik makend van tekst:

def actualString = nieuw bestand ('src / main / resources / ioInput.txt'). tekst

En als u met binaire bestanden werkt, is er de bytes methode:

def content = nieuw bestand ('src / main / resources / binaryExample.jpg'). bytes

3. Bestanden schrijven

Voordat we naar bestanden gaan schrijven, stellen we de tekst op die we zullen uitvoeren:

def outputLines = ['Lijn één van uitvoervoorbeeld', 'Lijn twee van uitvoervoorbeeld', 'Lijn drie van uitvoervoorbeeld']

3.1. Schrijven met schrijver

Net als bij het lezen van een bestand, we kunnen ook gemakkelijk een BufferedWriter uit een het dossier voorwerp.

Laten we gebruiken withWriter om een BufferedWriter en geef het door aan een afsluiting:

def outputFileName = 'src / main / resources / ioOutput.txt' nieuw bestand (outputFileName) .withWriter {schrijver -> outputLines.each {regel -> writer.writeLine regel}}

Gebruik makend van withReader zal de bron sluiten als er een uitzondering optreedt.

Groovy heeft ook een methode om het BufferedWriter voorwerp. Laten we een BufferedWriter gebruik makend van newWriter:

def outputFileName = 'src / main / resources / ioOutput.txt' def writer = nieuw bestand (outputFileName) .newWriter () outputLines.forEach {regel -> writer.writeLine regel} writer.flush () writer.close ()

Wij zijn verantwoordelijk voor het doorspoelen en sluiten van onze BufferedWriter bezwaar maken wanneer we gebruiken newWriter.

3.2. Schrijven met uitvoerstreams

Als we binaire gegevens wegschrijven, we kunnen een OutputStream met behulp van een van beide withOutputStream of newOutputStream.

Laten we wat bytes naar een bestand schrijven met withOutputStream:

byte [] outBytes = [44, 88, 22] nieuw bestand (outputFileName) .withOutputStream {stream -> stream.write (outBytes)}

Laten we een OutputStream object met newOutputStream en gebruik het om enkele bytes te schrijven:

byte [] outBytes = [44, 88, 22] def os = nieuw bestand (outputFileName) .newOutputStream () os.write (outBytes) os.close ()

gelijk aan InputStream, BufferedReader, en BufferedWriter, zijn wij verantwoordelijk voor het sluiten van de OutputStream onszelf als we gebruiken newOutputStream.

3.3. Schrijven met de << Operator

Omdat het schrijven van tekst naar bestanden zo gewoon is, is de << operator biedt deze functie rechtstreeks aan.

Laten we de << operator om enkele eenvoudige regels tekst te schrijven:

def ln = System.getProperty ('line.separator') def outputFileName = 'src / main / resources / ioOutput.txt' nieuw bestand (outputFileName) << "Regel één van uitvoervoorbeeld $ {ln}" + "Regel twee van uitvoervoorbeeld $ {ln} Regel drie van uitvoervoorbeeld "

3.4. Binaire gegevens schrijven met bytes

We zagen eerder in het artikel dat we alle bytes uit een binair bestand kunnen halen door simpelweg de bytes veld.

Laten we binaire gegevens op dezelfde manier schrijven:

def outputFileName = 'src / main / resources / ioBinaryOutput.bin' def outputFile = nieuw bestand (outputFileName) byte [] outBytes = [44, 88, 22] outputFile.bytes = outBytes

4. Door bestandsstructuren bladeren

Groovy biedt ons ook gemakkelijke manieren om met bestandsstructuren te werken. In dit gedeelte gaan we dat doen met eachFile, eachDir en hun varianten en de traverse methode.

4.1. Lijstbestanden met eachFile

Laten we een lijst maken van alle bestanden en mappen in een map met eachFile:

nieuw bestand ('src / main / resources'). eachFile {file -> println file.name}

Een ander veelvoorkomend scenario bij het werken met bestanden is de noodzaak om de bestanden te filteren op basis van de bestandsnaam. Laten we alleen de bestanden opsommen die beginnen met "io" en eindigen op ".txt" met eachFileMatch en een reguliere expressie:

nieuw bestand ('src / main / resources'). eachFileMatch (~ / io. * \. txt /) {file -> println file.name}

De eachFile en eachFileMatch methoden geven alleen de inhoud van de map op het hoogste niveau weer. Groovy stelt ons ook in staat om te beperken wat de eachFile methoden retourneren door een Bestandstype naar de methoden. De mogelijkheden zijn IEDER, BESTANDEN, en DIRECTORIES.

Laten we recursief alle bestanden weergeven met eachFileRecurse en het te voorzien van een Bestandstype van BESTANDEN:

nieuw bestand ('src / main'). eachFileRecurse (FileType.FILES) {file -> println "$ file.parent $ file.name"}

De eachFile methoden gooien een IllegalArgumentException als we ze een pad naar een bestand geven in plaats van een map.

Groovy biedt ook de eachDir methoden om alleen met mappen te werken. We kunnen gebruiken eachDir en zijn varianten om hetzelfde te bereiken als het gebruik van eachFile met een Bestandstype van DIRECTORIES.

Laten we mappen recursief weergeven met eachFileRecurse:

nieuw bestand ('src / main'). eachFileRecurse (FileType.DIRECTORIES) {file -> println "$ file.parent $ file.name"}

Laten we nu hetzelfde doen met eachDirRecurse:

nieuw bestand ('src / main'). eachDirRecurse {dir -> println "$ dir.parent $ dir.name"}

4.2. Listing Files with Traverse

Voor meer gecompliceerde gevallen van het doorlopen van mappen kunnen we de traverse methode. Het werkt op dezelfde manier als eachFileRecurse maar biedt de mogelijkheid om terug te keren FileVisitResult objecten om de verwerking te controleren.

Laten we gebruiken traverse op onze src / main directory en sla het verwerken van de boom onder de groovy directory:

nieuw bestand ('src / main'). traverse {file -> if (file.directory && file.name == 'groovy') {FileVisitResult.SKIP_SUBTREE} anders {println "$ file.parent - $ file.name"} }

5. Werken met gegevens en objecten

5.1. Primitieven serialiseren

In Java kunnen we DataInputStream en DataOutputStream om primitieve gegevensvelden te serialiseren. Groovy voegt hier ook handige uitbreidingen aan toe.

Laten we wat primitieve gegevens opzetten:

String message = 'Dit is een geserialiseerde string' int length = message.length () boolean valid = true

Laten we nu onze gegevens serialiseren naar een bestand met withDataOutputStream:

nieuw bestand ('src / main / resources / ioData.txt'). withDataOutputStream {out -> out.writeUTF (bericht) out.writeInt (lengte) out.writeBoolean (geldig)}

En lees het terug in het gebruik withDataInputStream:

String loadedMessage = "" int loadedLength boolean loadedValid nieuw bestand ('src / main / resources / ioData.txt'). WithDataInputStream {is -> loadedMessage = is.readUTF () loadedLength = is.readInt () loadedValid = is.readBoolean ( )}

Net als de andere met* methoden, withDataOutputStream en withDataInputStream passeer de stroom naar de sluiting en zorg ervoor dat deze goed is gesloten.

5.2. Objecten serialiseren

Groovy bouwt ook voort op Java's ObjectInputStream en ObjectOutputStream zodat we objecten die implementeren Serialiseerbaar.

Laten we eerst een klasse definiëren die implementeert Serialiseerbaar:

class Taak implementeert Serializable {String description Date startDate Date dueDate int status}

Laten we nu een instantie maken van Taak die we kunnen serialiseren naar een bestand:

Taak taak = nieuwe taak (beschrijving: 'Verwijder de prullenbak', startDate: nieuwe datum (), status: 0)

Met onze Taak object in de hand, laten we het serialiseren naar een bestand met withObjectOutputStream:

nieuw bestand ('src / main / resources / ioSerializedObject.txt'). withObjectOutputStream {out -> out.writeObject (task)}

Laten we tot slot onze lezen Taak weer in gebruik withObjectInputStream:

Taak taskRead new File ('src / main / resources / ioSerializedObject.txt'). WithObjectInputStream {is -> taskRead = is.readObject ()}

De methoden die we hebben gebruikt, withObjectOutputStream en withObjectInputStream, geef de stroom een ​​afsluiting en behandel de bronnen op de juiste manier, net als bij de ander met* methoden.

6. Conclusie

In dit artikel hebben we de functionaliteit onderzocht die Groovy toevoegt aan bestaande Java File I / O-klassen. We hebben deze functionaliteit gebruikt om bestanden te lezen en te schrijven, met directorystructuren te werken en gegevens en objecten te serialiseren.

We hebben slechts een paar van de hulpmethoden aangeroerd, dus het is de moeite waard om in de documentatie van Groovy te graven om te zien wat het nog meer toevoegt aan Java's I / O-functionaliteit.

De voorbeeldcode is beschikbaar op GitHub.


$config[zx-auto] not found$config[zx-overlay] not found