Hoe een bestand in Java te lezen

1. Overzicht

In deze tutorial verkennen we verschillende manieren om gelezen uit een bestand in Java.

Eerst zullen we zien hoe we een bestand kunnen laden vanuit het klassenpad, een URL of vanuit een JAR-bestand met behulp van standaard Java-klassen.

Ten tweede zullen we zien hoe we de inhoud kunnen lezen met BufferedReader, Scanner, StreamTokenizer, DataInputStream, SequenceInputStream, en FileChannel. We zullen ook bespreken hoe u een UTF-8-gecodeerd bestand kunt lezen.

Ten slotte onderzoeken we de nieuwe technieken om een ​​bestand te laden en te lezen in Java 7 en Java 8.

Dit artikel maakt deel uit van de serie "Java - Back to Basic" hier op Baeldung.

2. Installatie

2.1 Invoerbestand

In de meeste voorbeelden in dit artikel zullen we een tekstbestand met bestandsnaam lezen bestandTest.txt die één regel bevat:

Hallo Wereld!

In een paar voorbeelden zullen we een ander bestand gebruiken. In deze gevallen vermelden we het bestand en de inhoud expliciet.

2.2 Hulpmethode

We zullen een set testvoorbeelden gebruiken met alleen Java-kernklassen, en in de tests zullen we beweringen gebruiken met Hamcrest-matchers.

Tests zullen iets gemeen hebben readFromInputStream methode die een InputStream naar Draad voor het gemakkelijker bevestigen van resultaten:

private String readFromInputStream (InputStream inputStream) gooit IOException {StringBuilder resultStringBuilder = nieuwe StringBuilder (); probeer (BufferedReader br = nieuwe BufferedReader (nieuwe InputStreamReader (inputStream))) {String line; while ((line = br.readLine ())! = null) {resultStringBuilder.append (regel) .append ("\ n"); }} return resultStringBuilder.toString (); }

Merk op dat er andere manieren zijn om hetzelfde resultaat te bereiken. Voor enkele alternatieven kunt u dit artikel raadplegen.

3. Lezen van een bestand van het Classpath

3.1. Met behulp van standaard Java

In dit gedeelte wordt uitgelegd hoe u een bestand leest dat beschikbaar is op een klassenpad. We lezen de " bestandTest.txt ”Beschikbaar onder src / main / resources :

@Test openbare leegte gegevenFileNameAsAbsolutePath_whenUsingClasspath_thenFileData () {String verwachtData = "Hallo wereld!"; Klasse clazz = FileOperationsTest.class; InputStream inputStream = clazz.getResourceAsStream ("/ fileTest.txt"); String data = readFromInputStream (inputStream); Assert.assertThat (data, bevatString (verwachteData)); }

In het bovenstaande codefragment hebben we de huidige klasse gebruikt om een ​​bestand te laden met getResourceAsStream methode en gaf het absolute pad van het te laden bestand door.

Dezelfde methode is beschikbaar op een ClassLoader bijvoorbeeld ook:

ClassLoader classLoader = getClass (). GetClassLoader (); InputStream inputStream = classLoader.getResourceAsStream ("fileTest.txt"); String data = readFromInputStream (inputStream);

We verkrijgen de classLoader van de huidige klasse met getClass (). getClassLoader () .

Het belangrijkste verschil is dat bij gebruik van de getResourceAsStream op een ClassLoader het pad wordt bijvoorbeeld als absoluut behandeld, beginnend bij de root van het klassenpad.

Bij gebruik tegen een Klasse voorbeeld , het pad kan relatief zijn ten opzichte van het pakket, of een absoluut pad, dat wordt aangegeven door de voorlopende schuine streep.

Houd er natuurlijk rekening mee dat open stromen in de praktijk altijd gesloten moeten zijn, zoals de InputStream in ons voorbeeld:

InputStream inputStream = null; probeer {File file = new File (classLoader.getResource ("fileTest.txt"). getFile ()); inputStream = nieuwe FileInputStream (bestand); // ...} eindelijk {if (inputStream! = null) {probeer {inputStream.close (); } catch (IOException e) {e.printStackTrace (); }}}

3.2. De ... gebruiken commons-io Bibliotheek

Een andere veel voorkomende optie is het gebruik van de FileUtils klasse van de commons-io pakket:

@Test openbare leegte gegevenFileName_whenUsingFileUtils_thenFileData () {String verwachtData = "Hallo wereld!"; ClassLoader classLoader = getClass (). GetClassLoader (); Bestand bestand = nieuw bestand (classLoader.getResource ("fileTest.txt"). GetFile ()); String data = FileUtils.readFileToString (bestand, "UTF-8"); assertEquals (verwachteData, data.trim ()); }

Hier passeren we de het dossier bezwaar maken tegen de methode readFileToString () van FileUtils klasse. Deze utility class slaagt erin om de inhoud te laden zonder de noodzaak om standaardcode te schrijven om een InputStream instantie en lees gegevens.

Dezelfde bibliotheek biedt ook de IOUtilsklasse:

@Test openbare leegte gegevenFileName_whenUsingIOUtils_thenFileData () {String verwachtData = "Hallo wereld!"; FileInputStream fis = nieuwe FileInputStream ("src / test / resources / fileTest.txt"); String data = IOUtils.toString (fis, "UTF-8"); assertEquals (verwachteData, data.trim ()); }

Hier passeren we de FileInputStream bezwaar maken tegen de methode toString () van IOUtils klasse. Deze utility class slaagt erin om de inhoud te laden zonder de noodzaak om standaardcode te schrijven om een InputStream instantie en lees gegevens.

4. Lezen met BufferedReader

Laten we ons nu concentreren op verschillende manieren om de inhoud van een bestand te ontleden.

We beginnen met een eenvoudige manier om uit een bestand te lezen met BufferedReader:

@Test public void whenReadWithBufferedReader_thenCorrect () gooit IOException {String verwacht_value = "Hallo wereld!"; String-bestand; BufferedReader-lezer = nieuwe BufferedReader (nieuwe FileReader (bestand)); String currentLine = reader.readLine (); reader.close (); assertEquals (verwachte_waarde, currentLine); }

Let daar op Lees regel() zal terugkeren nul wanneer het einde van het bestand is bereikt.

5. Lezen vanuit een bestand met Java NIO

In JDK7 is het NIO-pakket aanzienlijk bijgewerkt.

Laten we een voorbeeld bekijken met de Bestanden klasse en de readAllLines methode. De readAllLines methode accepteert een Pad.

Pad class kan worden beschouwd als een upgrade van de java.io.File met enkele aanvullende bewerkingen.

5.1. Een klein bestand lezen

De volgende code laat zien hoe u een klein bestand kunt lezen met het nieuwe Bestanden klasse:

@Test public void whenReadSmallFileJava7_thenCorrect () gooit IOException {String verwacht_value = "Hallo wereld!"; Padpad = Paths.get ("src / test / resources / fileTest.txt"); String read = Files.readAllLines (pad) .get (0); assertEquals (verwachte_waarde, gelezen); }

Merk op dat u de readAllBytes () methode ook als u binaire gegevens nodig heeft.

5.2. Een groot bestand lezen

Als we een groot bestand willen lezen met Bestanden klasse, kunnen we de BufferedReader:

De volgende code leest het bestand met behulp van het nieuwe Bestanden klasse en BufferedReader:

@Test public void whenReadLargeFileJava7_thenCorrect () gooit IOException {String verwacht_value = "Hallo wereld!"; Padpad = Paths.get ("src / test / resources / fileTest.txt"); BufferedReader-lezer = Files.newBufferedReader (pad); String line = reader.readLine (); assertEquals (verwachte_waarde, regel); }

5.3. Een bestand lezen met Files.lines ()

JDK8 biedt de lijnen () methode binnen de Bestanden klasse. Het retourneert een Stroom van String-elementen.

Laten we eens kijken naar een voorbeeld van hoe gegevens in bytes kunnen worden gelezen en gedecodeerd met UTF-8-tekenset.

De volgende code leest het bestand met behulp van het nieuwe Files.lines ():

@Test openbare leegte gegevenFilePath_whenUsingFilesLines_thenFileData () {String verwachtData = "Hallo wereld!"; Padpad = Paths.get (getClass (). GetClassLoader () .getResource ("fileTest.txt"). ToURI ()); Stroomlijnen = Files.lines (pad); String data = lines.collect (Collectors.joining ("\ n")); lines.close (); Assert.assertEquals (verwachteData, data.trim ()); }

Als we Stream gebruiken met IO-kanalen zoals bestandsbewerkingen, moeten we de stream expliciet sluiten met behulp van de dichtbij() methode.

Zoals we kunnen zien, is de Bestanden API biedt een andere gemakkelijke manier om de inhoud van het bestand in een Draad.

Laten we in de volgende secties eens kijken naar andere, minder gebruikelijke methoden om een ​​bestand te lezen, die in sommige situaties geschikt kunnen zijn.

6. Lezen met Scanner

Laten we vervolgens een Scanner om uit het bestand te lezen. Hier gebruiken we witruimte als scheidingsteken:

@Test public void whenReadWithScanner_thenCorrect () gooit IOException {String file = "src / test / resources / fileTest.txt"; Scanner scanner = nieuwe scanner (nieuw bestand (bestand)); scanner.useDelimiter (""); assertTrue (scanner.hasNext ()); assertEquals ("Hallo,", scanner.next ()); assertEquals ("wereld!", scanner.next ()); scanner.close (); }

Merk op dat het standaard scheidingsteken de witruimte is, maar meerdere scheidingstekens kunnen worden gebruikt met een Scanner.

De klasse Scanner is handig bij het lezen van inhoud van de console of wanneer de inhoud primitieve waarden bevat, met een bekend scheidingsteken (bijvoorbeeld: een lijst met gehele getallen gescheiden door een spatie).

7. Lezen met StreamTokenizer

Laten we vervolgens een tekstbestand in tokens lezen met behulp van een StreamTokenizer.

De manier waarop de tokenizer werkt is - eerst moeten we uitzoeken wat het volgende token is - String of getal; we doen dat door te kijken naar de tokenizer.ttype veld.

Vervolgens lezen we het daadwerkelijke token op basis van dit type:

  • tokenizer.nval - als het type een nummer was
  • tokenizer.sval - als het type een String was

In dit voorbeeld gebruiken we een ander invoerbestand dat simpelweg het volgende bevat:

Hallo 1

De volgende code leest zowel de tekenreeks als het nummer uit het bestand:

@Test public void whenReadWithStreamTokenizer_thenCorrectTokens () gooit IOException {String file = "src / test / resources / fileTestTokenizer.txt"; FileReader-lezer = nieuwe FileReader (bestand); StreamTokenizer-tokenizer = nieuwe StreamTokenizer (lezer); // token 1 tokenizer.nextToken (); assertEquals (StreamTokenizer.TT_WORD, tokenizer.ttype); assertEquals ("Hallo", tokenizer.sval); // token 2 tokenizer.nextToken (); assertEquals (StreamTokenizer.TT_NUMBER, tokenizer.ttype); assertEquals (1, tokenizer.nval, 0.0000001); // token 3 tokenizer.nextToken (); assertEquals (StreamTokenizer.TT_EOF, tokenizer.ttype); reader.close (); }

Merk op hoe het einde van bestandstoken aan het einde wordt gebruikt.

Deze benadering is handig voor het parseren van een invoerstroom in tokens.

8. Lezen met DataInputStream

We kunnen gebruiken DataInputStream om binair of primitief gegevenstype uit een bestand te lezen.

De volgende test leest het bestand met een DataInputStream:

@Test public void whenReadWithDataInputStream_thenCorrect () gooit IOException {String verwachtValue = "Hallo wereld!"; String-bestand; String resultaat = null; DataInputStream-lezer = nieuwe DataInputStream (nieuwe FileInputStream (bestand)); int nBytesToRead = reader.available (); if (nBytesToRead> 0) {byte [] bytes = nieuwe byte [nBytesToRead]; reader.read (bytes); resultaat = nieuwe String (bytes); } assertEquals (verwachte waarde, resultaat); }

9. Lezen met FileChannel

Als we een groot bestand lezen, FileChannel kan sneller zijn dan standaard IO.

De volgende code leest databytes uit het bestand met FileChannel en RandomAccessFile:

@Test public void whenReadWithFileChannel_thenCorrect () gooit IOException {String verwacht_value = "Hallo wereld!"; String file = "src / test / resources / fileTest.txt"; RandomAccessFile reader = nieuw RandomAccessFile (bestand, "r"); FileChannel-kanaal = reader.getChannel (); int bufferSize = 1024; if (bufferSize> channel.size ()) {bufferSize = (int) channel.size (); } ByteBuffer buff = ByteBuffer.allocate (bufferSize); channel.read (buff); buff.flip (); assertEquals (verwachte_waarde, nieuwe String (buff.array ())); kanaal.close (); reader.close (); }

10. Lezen van een UTF-8 gecodeerd bestand

Laten we nu eens kijken hoe we een UTF-8-gecodeerd bestand kunnen lezen met BufferedReader. In dit voorbeeld zullen we een bestand lezen dat Chinese karakters bevat:

@Test openbare leegte whenReadUTFEncodedFile_thenCorrect () gooit IOException {String verwachte_waarde = "青 空"; String file = "src / test / resources / fileTestUtf8.txt"; BufferedReader-lezer = nieuwe BufferedReader (nieuwe InputStreamReader (nieuwe FileInputStream (bestand), "UTF-8")); String currentLine = reader.readLine (); reader.close (); assertEquals (verwachte_waarde, currentLine); }

11. Inhoud van URL lezen

Om inhoud van een URL te lezen, gebruiken we '/"URL in ons voorbeeld als:

@Test openbare ongeldig gegevenURLName_whenUsingURL_thenFileData () {String verwachteData = "Baeldung"; URL urlObject = nieuwe URL ("/"); URLConnection urlConnection = urlObject.openConnection (); InputStream inputStream = urlConnection.getInputStream (); String data = readFromInputStream (inputStream); Assert.assertThat (data, bevatString (verwachteData)); }

Er zijn ook alternatieve manieren om verbinding te maken met een URL. Hier hebben we de URL en URLConnection klasse beschikbaar in de standaard SDK.

12. Een bestand uit een JAR lezen

Om een ​​bestand te lezen dat zich in een JAR-bestand bevindt, hebben we een JAR nodig met een bestand erin. Voor ons voorbeeld zullen we lezen "LICENTIE.txt" van de "hamcrest-bibliotheek-1.3.jar" het dossier:

@Test openbare ongeldig gegevenFileName_whenUsingJarFile_thenFileData () {String verwachtData = "BSD-licentie"; Class clazz = Matchers.class; InputStream inputStream = clazz.getResourceAsStream ("/ LICENSE.txt"); String data = readFromInputStream (inputStream); Assert.assertThat (data, bevatString (verwachteData)); }

Hier willen we laden LICENTIE.txt die zich in de Hamcrest-bibliotheek bevindt, dus we zullen de Matcher's klasse die helpt om een ​​bron te krijgen. Hetzelfde bestand kan ook worden geladen met de classloader.

13. Conclusie

Zoals u kunt zien, zijn er veel mogelijkheden om een ​​bestand te laden en er gegevens uit te lezen met behulp van gewoon Java.

U kunt een bestand vanaf verschillende locaties laden, zoals classpath, URL of jar-bestanden.

Dan kun je gebruik maken van BufferedReader regel voor regel lezen, Scanner lezen met verschillende scheidingstekens, StreamTokenizer om een ​​bestand in tokens te lezen, DataInputStream om binaire gegevens en primitieve gegevenstypen te lezen, SequenceInput Stream om meerdere bestanden in één stream te linken, FileChannel om sneller te lezen van grote bestanden, enz.

Je kunt de broncode vinden in de volgende GitHub-opslagplaats.


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