Sådan læses en fil i Java

1. Oversigt

I denne vejledning undersøger vi forskellige måder at læses fra en fil i Java.

Først ser vi, hvordan man indlæser en fil fra klassestien, en URL eller fra en JAR-fil ved hjælp af standard Java-klasser.

For det andet vil vi se, hvordan man læser indholdet med BufferedReader, Scanner, StreamTokenizer, DataInputStream, SekvensInputStream, og FileChannel. Vi vil også diskutere, hvordan man læser en UTF-8-kodet fil.

Endelig vil vi undersøge de nye teknikker til at indlæse og læse en fil i Java 7 og Java 8.

Denne artikel er en del af "Java - Back to Basic" -serien her på Baeldung.

2. Opsætning

2.1 Inputfil

I de fleste eksempler i denne artikel læser vi en tekstfil med filnavn fileTest.txt der indeholder en linje:

Hej Verden!

I et par eksempler bruger vi en anden fil. I disse tilfælde nævner vi filen og dens indhold eksplicit.

2.2 Hjælpemetode

Vi bruger et sæt testeksempler, der kun bruger Java-klasser, og i testene bruger vi påstande ved hjælp af Hamcrest-matchere.

Test deler en fælles readFromInputStream metode, der omdanner en InputStream til Snor for lettere at hæve resultaterne:

private String readFromInputStream (InputStream inputStream) kaster IOException {StringBuilder resultStringBuilder = ny StringBuilder (); prøv (BufferedReader br = ny BufferedReader (ny InputStreamReader (inputStream))) {Strenglinje; mens ((line = br.readLine ())! = null) {resultStringBuilder.append (line) .append ("\ n"); }} returner resultStringBuilder.toString (); }

Bemærk, at der er andre måder at opnå det samme resultat på. Du kan se denne artikel for nogle alternativer.

3. Læsning af en fil fra klassestien

3.1. Brug af Standard Java

Dette afsnit forklarer, hvordan man læser en fil, der er tilgængelig på en klassesti. Vi læser “ fileTest.txt ”Tilgængelig under src / main / ressourcer :

@Test offentlig ugyldighed givenFileNameAsAbsolutePath_whenUsingClasspath_thenFileData () {String expectData = "Hej verden!"; Class clazz = FileOperationsTest.class; InputStream inputStream = clazz.getResourceAsStream ("/ fileTest.txt"); Strengdata = readFromInputStream (inputStream); Assert.assertThat (data, indeholderString (forventetData)); }

I ovenstående kodestykke brugte vi den aktuelle klasse til at indlæse en fil ved hjælp af getResourceAsStream metode og bestod den absolutte sti til filen, der skal indlæses.

Den samme metode er tilgængelig på en ClassLoader eksempel også:

ClassLoader classLoader = getClass () getClassLoader (); InputStream inputStream = classLoader.getResourceAsStream ("fileTest.txt"); Strengdata = readFromInputStream (inputStream);

Vi får classLoader af den aktuelle klasse ved hjælp af getClass () getClassLoader () .

Den største forskel er, at når du bruger getResourceAsStream på en ClassLoader eksempelvis behandles stien som absolut startende fra rodstien til klassestien.

Når det bruges mod en Klasse eksempel , stien kan være i forhold til pakken eller en absolut sti, som er antydet af den førende skråstreg.

Bemærk naturligvis, at åbne streams i praksis altid skal være lukket, såsom InputStream i vores eksempel:

InputStream inputStream = null; prøv {File file = new File (classLoader.getResource ("fileTest.txt"). getFile ()); inputStream = ny FileInputStream (fil); // ...} endelig {if (inputStream! = null) {prøv {inputStream.close (); } fange (IOException e) {e.printStackTrace (); }}}

3.2. Bruger commons-io Bibliotek

En anden almindelig mulighed er at bruge FileUtils klasse af commons-io pakke:

@Test offentlig ugyldighed givenFileName_whenUsingFileUtils_thenFileData () {String expectData = "Hej verden!"; ClassLoader classLoader = getClass () getClassLoader (); Filfil = ny fil (classLoader.getResource ("fileTest.txt"). GetFile ()); String data = FileUtils.readFileToString (fil, "UTF-8"); assertEquals (expectData, data.trim ()); }

Her passerer vi Fil modsætter sig metoden readFileToString () af FileUtils klasse. Denne værktøjsklasse formår at indlæse indholdet uden behovet for at skrive nogen kedelpladekode for at oprette en InputStream forekomme og læse data.

Det samme bibliotek tilbyder også IOUtilsklasse:

@Test offentligt ugyldigt givenFileName_whenUsingIOUtils_thenFileData () {String expectData = "Hej verden!"; FileInputStream fis = ny FileInputStream ("src / test / resources / fileTest.txt"); Strengdata = IOUtils.toString (fis, "UTF-8"); assertEquals (expectData, data.trim ()); }

Her passerer vi FileInputStream modsætter sig metoden toString () af IOUtils klasse. Denne hjælpeprogram klarer at indlæse indholdet uden behov for at skrive nogen kedelpladekode for at oprette en InputStream forekomme og læse data.

4. Læsning med BufferedReader

Lad os nu fokusere på forskellige måder at analysere indholdet af en fil på.

Vi starter med en enkel måde at læse fra en fil ved hjælp af BufferedReader:

@Test offentlig ugyldig nårReadWithBufferedReader_thenCorrect () kaster IOException {String expect_value = "Hej verden!"; Strengfil; BufferedReader-læser = ny BufferedReader (ny FileReader (fil)); Streng currentLine = reader.readLine (); reader.close (); assertEquals (forventet_værdi, nuværendeLine); }

Noter det readLine () kommer tilbage nul når slutningen af ​​filen er nået.

5. Læsning fra en fil ved hjælp af Java NIO

I JDK7 blev NIO-pakken opdateret betydeligt.

Lad os se på et eksempel ved hjælp af Filer klasse og readAllLines metode. Det readAllLines metode accepterer en Sti.

Sti klasse kan betragtes som en opgradering af java.io-fil med nogle yderligere operationer på plads.

5.1. Læsning af en lille fil

Den følgende kode viser, hvordan man læser en lille fil ved hjælp af den nye Filer klasse:

@Test offentlig ugyldig nårReadSmallFileJava7_thenCorrect () kaster IOException {String expect_value = "Hej verden!"; Sti sti = Paths.get ("src / test / resources / fileTest.txt"); String read = Files.readAllLines (sti) .get (0); assertEquals (forventet_værdi, læs); }

Bemærk, at du kan bruge readAllBytes () metode også, hvis du har brug for binære data.

5.2. Læsning af en stor fil

Hvis vi vil læse en stor fil med Filer klasse, kan vi bruge BufferedReader:

Den følgende kode læser filen ved hjælp af den nye Filer klasse og BufferedReader:

@Test offentlig ugyldig nårReadLargeFileJava7_thenCorrect () kaster IOException {String expect_value = "Hej verden!"; Sti sti = Paths.get ("src / test / resources / fileTest.txt"); BufferedReader reader = Files.newBufferedReader (sti); String line = reader.readLine (); assertEquals (forventet_værdi, linje); }

5.3. Læsning af en fil ved hjælp af Files.lines ()

JDK8 tilbyder linjer () metode inde i Filer klasse. Det returnerer en Strøm af strengelementer.

Lad os se på et eksempel på, hvordan man læser data i bytes og afkoder ved hjælp af UTF-8-tegnsæt.

Den følgende kode læser filen ved hjælp af den nye Files.lines ():

@Test offentlig ugyldighed givenFilePath_whenUsingFilesLines_thenFileData () {String expectData = "Hej verden!"; Sti sti = Paths.get (getClass (). GetClassLoader () .getResource ("fileTest.txt"). ToURI ()); Stream linjer = Files.lines (sti); Strengdata = lines.collect (Collectors.joining ("\ n")); lines.close (); Assert.assertEquals (expectData, data.trim ()); }

Brug af Stream med IO-kanaler som filhandlinger er vi nødt til at lukke strømmen eksplicit ved hjælp af tæt() metode.

Som vi kan se, er Filer API tilbyder en anden nem måde at læse filindholdet på i Snor.

Lad os i de næste sektioner se på andre, mindre almindelige metoder til at læse en fil, der kan være passende i nogle situationer.

6. Læsning med Scanner

Lad os derefter bruge en Scanner at læse fra filen. Her bruger vi mellemrum som afgrænser:

@Test offentlig ugyldigt nårReadWithScanner_thenCorrect () kaster IOException {String file = "src / test / resources / fileTest.txt"; Scannerscanner = ny scanner (ny fil (fil)); scanner.useDelimiter (""); assertTrue (scanner.hasNext ()); assertEquals ("Hej", scanner.next ()); assertEquals ("verden!", scanner.next ()); scanner.close (); }

Bemærk, at standardafgrænsningen er det hvide område, men flere afgrænsere kan bruges med en Scanner.

Scannerklassen er nyttig, når du læser indhold fra konsollen, eller når indholdet indeholder primitive værdier, med en kendt afgrænser (f.eks. en liste over heltal adskilt af mellemrum).

7. Læsning med StreamTokenizer

Lad os derefter læse en tekstfil i tokens ved hjælp af en StreamTokenizer.

Den måde, som tokenizer fungerer på, er - først skal vi finde ud af, hvad det næste token er - String eller nummer; vi gør det ved at se på tokenizer.ttype Mark.

Derefter læser vi det faktiske token baseret på denne type:

  • tokenizer.nval - hvis typen var et tal
  • tokenizer.sval - hvis typen var en streng

I dette eksempel bruger vi en anden inputfil, der simpelthen indeholder:

Hej 1

Følgende kode læser både filen og nummeret fra filen:

@Test offentlig ugyldigt nårReadWithStreamTokenizer_thenCorrectTokens () kaster IOException {String file = "src / test / resources / fileTestTokenizer.txt"; FileReader-læser = ny FileReader (fil); StreamTokenizer tokenizer = ny StreamTokenizer (læser); // token 1 tokenizer.nextToken (); assertEquals (StreamTokenizer.TT_WORD, tokenizer.ttype); assertEquals ("Hej", 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 (); }

Bemærk, hvordan slutningen af ​​filtoken bruges i slutningen.

Denne tilgang er nyttig til at analysere en inputstrøm i tokens.

8. Læsning med DataInputStream

Vi kan bruge DataInputStream for at læse binær eller primitiv datatype fra en fil.

Den følgende test læser filen ved hjælp af a DataInputStream:

@Test offentlig ugyldig nårReadWithDataInputStream_thenCorrect () kaster IOException {String expectValue = "Hej verden!"; Strengfil; Strengresultat = null; DataInputStream-læser = ny DataInputStream (ny FileInputStream (fil)); int nBytesToRead = reader.available (); hvis (nBytesToRead> 0) {byte [] bytes = ny byte [nBytesToRead]; reader.read (bytes); resultat = ny streng (bytes); } assertEquals (forventet værdi, resultat); }

9. Læsning med FileChannel

Hvis vi læser en stor fil, FileChannel kan være hurtigere end standard IO.

Den følgende kode læser databytes fra filen ved hjælp af FileChannel og RandomAccessFile:

@Test offentlig ugyldig nårReadWithFileChannel_thenCorrect () kaster IOException {String expect_value = "Hej verden!"; Strengfil = "src / test / resources / fileTest.txt"; RandomAccessFile-læser = ny RandomAccessFile (fil, "r"); FileChannel channel = reader.getChannel (); int bufferSize = 1024; hvis (bufferSize> channel.size ()) {bufferSize = (int) channel.size (); } ByteBuffer buff = ByteBuffer.allocate (bufferSize); channel.read (buff); buff.flip (); assertEquals (forventet_værdi, ny streng (buff.array ())); channel.close (); reader.close (); }

10. Læsning af en UTF-8 kodet fil

Lad os nu se, hvordan man læser en UTF-8-kodet fil ved hjælp af BufferedReader. I dette eksempel læser vi en fil, der indeholder kinesiske tegn:

@Test offentlig ugyldig nårReadUTFEncodedFile_thenCorrect () kaster IOException {String expect_value = "青 空"; Strengfil = "src / test / resources / fileTestUtf8.txt"; BufferedReader-læser = ny BufferedReader (ny InputStreamReader (ny FileInputStream (fil), "UTF-8")); Streng currentLine = reader.readLine (); reader.close (); assertEquals (forventet_værdi, nuværendeLine); }

11. Læsning af indhold fra URL

For at læse indhold fra en URL bruger vi “/”URL i vores eksempel som:

@Test offentligt ugyldigt givetURLName_whenUsingURL_thenFileData () {String expectData = "Baeldung"; URL urlObject = ny URL ("/"); URLConnection urlConnection = urlObject.openConnection (); InputStream inputStream = urlConnection.getInputStream (); Strengdata = readFromInputStream (inputStream); Assert.assertThat (data, indeholderString (forventetData)); }

Der er også alternative måder at oprette forbindelse til en URL på. Her brugte vi URL og URL-forbindelse klasse tilgængelig i standard SDK.

12. Læsning af en fil fra en JAR

For at læse en fil, der er placeret inde i en JAR-fil, har vi brug for en JAR med en fil inde i den. For vores eksempel vil vi læse “LICENSE.txt" fra "hamcrest-library-1.3.jar”Fil:

@Test offentlig ugyldighed givenFileName_whenUsingJarFile_thenFileData () {String expectData = "BSD License"; Class clazz = Matchers.class; InputStream inputStream = clazz.getResourceAsStream ("/ LICENSE.txt"); Strengdata = readFromInputStream (inputStream); Assert.assertThat (data, indeholderString (forventetData)); }

Her vil vi indlæse LICENSE.txt der er bosat i Hamcrest bibliotek, så vi bruger Matchers klasse, der hjælper med at få en ressource. Den samme fil kan også indlæses ved hjælp af classloader.

13. Konklusion

Som du kan se, er der mange muligheder for at indlæse en fil og læse data fra den ved hjælp af almindelig Java.

Du kan indlæse en fil fra forskellige placeringer som klassesti, URL eller jar-filer.

Så kan du bruge BufferedReader at læse linje for linje, Scanner at læse ved hjælp af forskellige afgrænsere, StreamTokenizer at læse en fil i tokens, DataInputStream at læse binære data og primitive datatyper, SequenceInput Stream at linke flere filer til en stream, FileChannel at læse hurtigere fra store filer osv.

Du kan finde kildekoden i følgende GitHub repo.