So lesen Sie eine Datei in Java

1. Übersicht

In diesem Tutorial werden verschiedene Möglichkeiten zum Lesen aus einer Datei in Java untersucht .

Zunächst erfahren Sie, wie Sie eine Datei aus dem Klassenpfad, einer URL oder einer JAR-Datei mithilfe von Standard-Java-Klassen laden.

Zweitens werden wir sehen, wie der Inhalt mit BufferedReader , Scanner , StreamTokenizer , DataInputStream , SequenceInputStream und FileChannel gelesen wird . Außerdem werden wir diskutieren, wie eine UTF-8-codierte Datei gelesen wird.

Schließlich werden wir die neuen Techniken zum Laden und Lesen einer Datei in Java 7 und Java 8 untersuchen.

Dieser Artikel ist Teil der Reihe „Java - Back to Basic“ hier auf Baeldung.

2. Setup

2.1 Eingabedatei

In den meisten Beispielen in diesem Artikel lesen wir eine Textdatei mit dem Dateinamen fileTest.txt , die eine Zeile enthält:

Hello, world!

In einigen Beispielen verwenden wir eine andere Datei. In diesen Fällen werden wir die Datei und ihren Inhalt explizit erwähnen.

2.2 Hilfsmethode

Wir werden eine Reihe von Testbeispielen nur mit Java-Kernklassen verwenden und in den Tests Aussagen mit Hamcrest-Matchern verwenden.

Tests verwenden eine gemeinsame readFromInputStream- Methode, die einen InputStream in einen String umwandelt , um die Bestätigung der Ergebnisse zu vereinfachen:

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

Beachten Sie, dass es andere Möglichkeiten gibt, dasselbe Ergebnis zu erzielen. In diesem Artikel finden Sie einige Alternativen.

3. Lesen einer Datei aus dem Klassenpfad

3.1. Verwenden von Standard Java

In diesem Abschnitt wird erläutert, wie Sie eine Datei lesen, die in einem Klassenpfad verfügbar ist. Wir werden die " fileTest.txt " lesen, die unter src / main / resources verfügbar ist :

@Test public void givenFileNameAsAbsolutePath_whenUsingClasspath_thenFileData() { String expectedData = "Hello, world!"; Class clazz = FileOperationsTest.class; InputStream inputStream = clazz.getResourceAsStream("/fileTest.txt"); String data = readFromInputStream(inputStream); Assert.assertThat(data, containsString(expectedData)); }

Im obigen Codeausschnitt haben wir die aktuelle Klasse zum Laden einer Datei mit der Methode getResourceAsStream verwendet und den absoluten Pfad der zu ladenden Datei übergeben.

Die gleiche Methode ist auch für eine ClassLoader- Instanz verfügbar :

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

Wir erhalten den classLoader der aktuellen Klasse mit getClass (). GetClassLoader () .

Der Hauptunterschied besteht darin, dass bei Verwendung von getResourceAsStream in einer ClassLoader- Instanz der Pfad ab dem Stammverzeichnis des Klassenpfads als absolut behandelt wird.

Bei der Anwendung gegen ein verwendete Klasse Beispiel , könnte der Pfad zu dem Paket, oder einen absoluten Pfad relativ sein, die durch den führenden Schrägstrich angedeutet ist.

Beachten Sie natürlich, dass offene Streams in der Praxis immer geschlossen sein sollten , wie z. B. der InputStream in unserem Beispiel:

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

3.2. Verwenden der Commons-Io- Bibliothek

Eine weitere häufige Option ist die Verwendung der FileUtils- Klasse des commons-io- Pakets:

@Test public void givenFileName_whenUsingFileUtils_thenFileData() { String expectedData = "Hello, world!"; ClassLoader classLoader = getClass().getClassLoader(); File file = new File(classLoader.getResource("fileTest.txt").getFile()); String data = FileUtils.readFileToString(file, "UTF-8"); assertEquals(expectedData, data.trim()); }

Hier übergeben wir das File- Objekt an die Methode readFileToString () der FileUtils- Klasse. Diese Utility-Klasse kann den Inhalt laden, ohne dass ein Boilerplate-Code geschrieben werden muss, um eine InputStream- Instanz zu erstellen und Daten zu lesen.

Die gleiche Bibliothek bietet auch die IOUtils anKlasse:

@Test public void givenFileName_whenUsingIOUtils_thenFileData() { String expectedData = "Hello, world!"; FileInputStream fis = new FileInputStream("src/test/resources/fileTest.txt"); String data = IOUtils.toString(fis, "UTF-8"); assertEquals(expectedData, data.trim()); }

Hier übergeben wir das FileInputStream- Objekt an die Methode toString () der IOUtils- Klasse. Diese Utility-Klasse kann den Inhalt laden, ohne dass Boilerplate-Code geschrieben werden muss, um eine InputStream- Instanz zu erstellen und Daten zu lesen.

4. Lesen mit BufferedReader

Konzentrieren wir uns nun auf verschiedene Möglichkeiten, den Inhalt einer Datei zu analysieren.

Wir beginnen mit einer einfachen Methode zum Lesen aus einer Datei mit BufferedReader:

@Test public void whenReadWithBufferedReader_thenCorrect() throws IOException { String expected_value = "Hello, world!"; String file; BufferedReader reader = new BufferedReader(new FileReader(file)); String currentLine = reader.readLine(); reader.close(); assertEquals(expected_value, currentLine); }

Beachten Sie, dass readline () wird wieder null , wenn das Ende der Datei erreicht ist.

5. Lesen aus einer Datei mit Java NIO

In JDK7 wurde das NIO-Paket erheblich aktualisiert.

Schauen wir uns ein Beispiel mit der Files- Klasse und der readAllLines- Methode an . Die readAllLines- Methode akzeptiert einen Pfad.

Pfad - Klasse kann als Upgrade des in Betracht gezogen wird java.io.File mit einigen zusätzlichen Operationen an Ort und Stelle.

5.1. Eine kleine Datei lesen

Der folgende Code zeigt, wie eine kleine Datei mit der neuen Files- Klasse gelesen wird :

@Test public void whenReadSmallFileJava7_thenCorrect() throws IOException { String expected_value = "Hello, world!"; Path path = Paths.get("src/test/resources/fileTest.txt"); String read = Files.readAllLines(path).get(0); assertEquals(expected_value, read); }

Note that you can use the readAllBytes() method as well if you need binary data.

5.2. Reading a Large File

If we want to read a large file with Files class, we can use the BufferedReader:

The following code reads the file using the new Files class and BufferedReader:

@Test public void whenReadLargeFileJava7_thenCorrect() throws IOException { String expected_value = "Hello, world!"; Path path = Paths.get("src/test/resources/fileTest.txt"); BufferedReader reader = Files.newBufferedReader(path); String line = reader.readLine(); assertEquals(expected_value, line); }

5.3. Reading a File Using Files.lines()

JDK8 offers the lines() method inside the Files class. It returns a Stream of String elements.

Let’s look at an example of how to read data into bytes and decode using UTF-8 charset.

The following code reads the file using the new Files.lines():

@Test public void givenFilePath_whenUsingFilesLines_thenFileData() { String expectedData = "Hello, world!"; Path path = Paths.get(getClass().getClassLoader() .getResource("fileTest.txt").toURI()); Stream lines = Files.lines(path); String data = lines.collect(Collectors.joining("\n")); lines.close(); Assert.assertEquals(expectedData, data.trim()); }

Using Stream with IO channels like file operations, we need to close the stream explicitly using the close() method.

As we can see, the Files API offers another easy way to read the file contents into a String.

In the next sections, let's have a look at other, less common methods of reading a file, that may be appropriate in some situations.

6. Reading with Scanner

Next, let's use a Scanner to read from the File. Here, we'll use whitespace as the delimiter:

@Test public void whenReadWithScanner_thenCorrect() throws IOException { String file = "src/test/resources/fileTest.txt"; Scanner scanner = new Scanner(new File(file)); scanner.useDelimiter(" "); assertTrue(scanner.hasNext()); assertEquals("Hello,", scanner.next()); assertEquals("world!", scanner.next()); scanner.close(); }

Note that the default delimiter is the whitespace, but multiple delimiters can be used with a Scanner.

The Scanner class is useful when reading content from the console, or when the content contains primitive values, with a known delimiter (eg: a list of integers separated by space).

7. Reading with StreamTokenizer

Next, let's read a text file into tokens using a StreamTokenizer.

The way the tokenizer works is – first, we need to figure out what the next token is – String or number; we do that by looking at the tokenizer.ttype field.

Then, we'll read the actual token based on this type:

  • tokenizer.nval – if the type was a number
  • tokenizer.sval – if the type was a String

In this example we'll use a different input file which simply contains:

Hello 1

The following code reads from the file both the String and the number:

@Test public void whenReadWithStreamTokenizer_thenCorrectTokens() throws IOException { String file = "src/test/resources/fileTestTokenizer.txt"; FileReader reader = new FileReader(file); StreamTokenizer tokenizer = new StreamTokenizer(reader); // token 1 tokenizer.nextToken(); assertEquals(StreamTokenizer.TT_WORD, tokenizer.ttype); assertEquals("Hello", 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(); }

Note how the end of file token is used at the end.

This approach is useful for parsing an input stream into tokens.

8. Reading with DataInputStream

We can use DataInputStream to read binary or primitive data type from a file.

The following test reads the file using a DataInputStream:

@Test public void whenReadWithDataInputStream_thenCorrect() throws IOException { String expectedValue = "Hello, world!"; String file; String result = null; DataInputStream reader = new DataInputStream(new FileInputStream(file)); int nBytesToRead = reader.available(); if(nBytesToRead > 0) { byte[] bytes = new byte[nBytesToRead]; reader.read(bytes); result = new String(bytes); } assertEquals(expectedValue, result); }

9. Reading with FileChannel

If we are reading a large file, FileChannel can be faster than standard IO.

The following code reads data bytes from the file using FileChannel and RandomAccessFile:

@Test public void whenReadWithFileChannel_thenCorrect() throws IOException { String expected_value = "Hello, world!"; String file = "src/test/resources/fileTest.txt"; RandomAccessFile reader = new RandomAccessFile(file, "r"); FileChannel channel = reader.getChannel(); int bufferSize = 1024; if (bufferSize > channel.size()) { bufferSize = (int) channel.size(); } ByteBuffer buff = ByteBuffer.allocate(bufferSize); channel.read(buff); buff.flip(); assertEquals(expected_value, new String(buff.array())); channel.close(); reader.close(); }

10. Reading a UTF-8 Encoded File

Now, let's see how to read a UTF-8 encoded file using BufferedReader. In this example, we'll read a file that contains Chinese characters:

@Test public void whenReadUTFEncodedFile_thenCorrect() throws IOException { String expected_value = "青空"; String file = "src/test/resources/fileTestUtf8.txt"; BufferedReader reader = new BufferedReader (new InputStreamReader(new FileInputStream(file), "UTF-8")); String currentLine = reader.readLine(); reader.close(); assertEquals(expected_value, currentLine); }

11. Reading Content from URL

To read content from a URL, we will use “/” URL in our example as:

@Test public void givenURLName_whenUsingURL_thenFileData() { String expectedData = "Baeldung"; URL urlObject = new URL("/"); URLConnection urlConnection = urlObject.openConnection(); InputStream inputStream = urlConnection.getInputStream(); String data = readFromInputStream(inputStream); Assert.assertThat(data, containsString(expectedData)); }

There are also alternative ways of connecting to a URL. Here we used the URL and URLConnection class available in the standard SDK.

12. Reading a File from a JAR

To read a file which is located inside a JAR file, we will need a JAR with a file inside it. For our example we will read “LICENSE.txt” from the “hamcrest-library-1.3.jar” file:

@Test public void givenFileName_whenUsingJarFile_thenFileData() { String expectedData = "BSD License"; Class clazz = Matchers.class; InputStream inputStream = clazz.getResourceAsStream("/LICENSE.txt"); String data = readFromInputStream(inputStream); Assert.assertThat(data, containsString(expectedData)); }

Here we want to load LICENSE.txt that resides in Hamcrest library, so we will use the Matcher's class that helps to get a resource. The same file can be loaded using the classloader too.

13. Conclusion

As you can see, there are many possibilities for loading a file and reading data from it using plain Java.

You can load a file from various locations like classpath, URL or jar files.

Dann können Sie BufferedReader zum zeilenweisen Lesen verwenden , Scanner zum Lesen mit verschiedenen Trennzeichen, StreamTokenizer zum Einlesen einer Datei in Token, DataInputStream zum Lesen von Binärdaten und primitiven Datentypen, SequenceInput Stream zum Verknüpfen mehrerer Dateien zu einem Stream, FileChannel zum schnelleren Lesen von großen Dateien usw.

Den Quellcode finden Sie im folgenden GitHub-Repo.