Java Read Files

Java Read Files

Java provides several ways to read the content of a file. We'll explore a few common methods, from using the classic Scanner to the modern java.nio API.


1. Using java.util.Scanner

The Scanner class is a simple and effective way to parse text from a file. It can read a file line by line or token by token.

To use it, you create a Scanner object and pass a File object to its constructor.

Reading a File with `Scanner`

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Main { public static void main(String[] args) { try { File myObj = new File("filename.txt"); Scanner myReader = new Scanner(myObj); while (myReader.hasNextLine()) { String data = myReader.nextLine(); System.out.println(data); } myReader.close(); } catch (FileNotFoundException e) { System.out.println("An error occurred: File not found."); e.printStackTrace(); } } }


2. Using java.io.BufferedReader

For reading large files efficiently, BufferedReader is an excellent choice. It reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines.

It is often wrapped around a FileReader. Using try-with-resources is highly recommended.

Reading with `BufferedReader`

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Main { public static void main(String[] args) { try (BufferedReader reader = new BufferedReader(new FileReader("filename.txt"))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { System.err.println("Error reading file: " + e.getMessage()); } } }


3. Using java.nio.file.Files (Modern Approach)

For small to medium-sized files, the modern NIO.2 API provides a very convenient one-liner to read all lines of a file into a List of strings.

Reading with `Files.readAllLines()`

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

public class Main { public static void main(String[] args) { try { List<String> allLines = Files.readAllLines(Paths.get("filename.txt")); for (String line : allLines) { System.out.println(line); } } catch (IOException e) { System.err.println("Error reading file: " + e.getMessage()); } } }

Warning: Be careful using Files.readAllLines() on very large files, as it will attempt to load the entire file content into memory, which could lead to an OutOfMemoryError. For large files, the BufferedReader approach is safer.


Advanced: Modern Approach with Files.readString()

Introduced in Java 11, the Files.readString() method provides an incredibly simple way to read the entire contents of a file into a single String. This is perfect for smaller files where you need all the text at once.

Reading a File to a String

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Main { public static void main(String[] args) { Path path = Paths.get("filename.txt"); try { // Reads the entire file into memory as a String String content = Files.readString(path); System.out.println("File Content:\n" + content); } catch (IOException e) { System.err.println("Error reading file: " + e.getMessage()); } } }


Advanced: Reading Large Files with Files.lines() (Streams)

In the previous section, we warned that Files.readAllLines() can cause memory issues with large files. A more modern and memory-efficient alternative is Files.lines().

This method returns a Stream<String>. Instead of loading the entire file into memory at once, it lazily populates the stream as it is consumed. This makes it ideal for processing massive files efficiently.

Reading with Streams

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class Main { public static void main(String[] args) { Path path = Paths.get("large-file.txt"); // The try-with-resources block ensures the stream (and underlying file) is closed try (Stream<String> lines = Files.lines(path)) { // Process lines using the Stream API (e.g., filter and print) lines.filter(line -> line.contains("ERROR")) .forEach(System.out::println); } catch (IOException e) { System.err.println("Error reading file: " + e.getMessage()); } } }


Exercise

?

Which modern method should you use to memory-efficiently read a massive file line by line?