Comment lire un fichier en Java

1. Vue d'ensemble

Dans ce didacticiel, nous explorerons différentes façons de lire à partir d'un fichier en Java .

Tout d'abord, nous verrons comment charger un fichier à partir du classpath, d'une URL ou d'un fichier JAR, en utilisant les classes Java standard.

Deuxièmement, nous verrons comment lire le contenu avec BufferedReader , Scanner , StreamTokenizer , DataInputStream , SequenceInputStream et FileChannel . Nous discuterons également de la manière de lire un fichier encodé en UTF-8.

Enfin, nous explorerons les nouvelles techniques pour charger et lire un fichier en Java 7 et Java 8.

Cet article fait partie de la série «Java - Back to Basic» ici sur Baeldung.

2. Configuration

2.1 Fichier d'entrée

Dans la plupart des exemples de cet article, nous lirons un fichier texte avec le nom de fichier fileTest.txt qui contient une ligne:

Hello, world!

Dans quelques exemples, nous utiliserons un fichier différent. Dans ces cas, nous mentionnerons explicitement le fichier et son contenu.

2.2 Méthode d'assistance

Nous utiliserons un ensemble d'exemples de tests utilisant uniquement les classes Java de base, et dans les tests, nous utiliserons des assertions utilisant des correspondeurs Hamcrest.

Les tests partageront une méthode readFromInputStream commune qui transforme un InputStream en String pour une affirmation plus facile des résultats:

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(); }

Notez qu'il existe d'autres moyens d'obtenir le même résultat. Vous pouvez consulter cet article pour quelques alternatives.

3. Lecture d'un fichier à partir du Classpath

3.1. Utilisation de Java standard

Cette section explique comment lire un fichier disponible sur un chemin de classe. Nous lirons le " fileTest.txt " disponible sous src / main / resources :

@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)); }

Dans l'extrait de code ci-dessus, nous avons utilisé la classe actuelle pour charger un fichier à l'aide de la méthode getResourceAsStream et avons passé le chemin absolu du fichier à charger.

La même méthode est également disponible sur une instance ClassLoader :

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

Nous obtenons le classLoader de la classe courante en utilisant getClass (). GetClassLoader () .

La principale différence est que lors de l'utilisation de getResourceAsStream sur une instance ClassLoader , le chemin est traité comme absolu à partir de la racine du chemin de classe .

Lorsqu'il est utilisé avec une instance de classe , le chemin peut être relatif au package, ou un chemin absolu, qui est indiqué par la barre oblique.

Bien sûr, notez qu'en pratique, les flux ouverts doivent toujours être fermés , comme InputStream dans notre exemple:

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. Utilisation de la bibliothèque commons-io

Une autre option courante consiste à utiliser la classe FileUtils du package commons-io :

@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()); }

Ici, nous passons l' objet File à la méthode readFileToString () de la classe FileUtils . Cette classe utilitaire parvient à charger le contenu sans avoir à écrire de code standard pour créer une instance InputStream et lire les données.

La même bibliothèque propose également les IOUtilsclasse:

@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()); }

Ici, nous passons l' objet FileInputStream à la méthode toString () de la classe IOUtils . Cette classe utilitaire parvient à charger le contenu sans avoir à écrire de code standard pour créer une instance InputStream et lire les données.

4. Lecture avec BufferedReader

Concentrons-nous maintenant sur différentes manières d'analyser le contenu d'un fichier.

Nous allons commencer par un moyen simple de lire à partir d'un fichier en utilisant 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); }

Notez que readLine () retournera null lorsque la fin du fichier est atteinte.

5. Lecture à partir d'un fichier à l'aide de Java NIO

Dans JDK7, le package NIO a été considérablement mis à jour.

Regardons un exemple utilisant la classe Files et la méthode readAllLines . La méthode readAllLines accepte un Path.

La classe Path peut être considérée comme une mise à niveau de java.io.File avec quelques opérations supplémentaires en place.

5.1. Lire un petit fichier

Le code suivant montre comment lire un petit fichier à l'aide de la nouvelle classe Files :

@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.

Ensuite, vous pouvez utiliser BufferedReader pour lire ligne par ligne, Scanner pour lire à l'aide de différents délimiteurs, StreamTokenizer pour lire un fichier en jetons, DataInputStream pour lire les données binaires et les types de données primitifs, SequenceInput Stream pour lier plusieurs fichiers en un seul flux, FileChannel pour lire plus rapidement à partir de fichiers volumineux, etc.

Vous pouvez trouver le code source dans le référentiel GitHub suivant.