Read a File in Java: The Modern Way
Reading a file in Java used to be verbose. Since Java 7 (NIO.2) and Java 11 (readString), it's a one-liner. This guide covers the modern approaches and when to pick each.
Read a whole file as a string (Java 11+)
import java.nio.file.Files;
import java.nio.file.Path;
String content = Files.readString(Path.of("config.json"));
Default charset is UTF-8. Perfect for small configuration or template files.
Read a file line by line into a List
import java.util.List;
List<String> lines = Files.readAllLines(Path.of("data.txt"));
for (String line : lines) {
System.out.println(line);
}
Warning: readAllLines loads the entire file into memory. Don't use it for files larger than ~10 MB.
Stream large files line by line
import java.util.stream.Stream;
try (Stream<String> lines = Files.lines(Path.of("huge.log"))) {
lines.filter(l -> l.contains("ERROR"))
.limit(100)
.forEach(System.out::println);
}
Files.lines returns a lazy Stream. You must close it β the try-with-resources block does that for you. Handles multi-GB files in constant memory.
BufferedReader β classic but still useful
import java.io.BufferedReader;
try (BufferedReader reader = Files.newBufferedReader(Path.of("data.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
// process line
}
}
Use when you need fine control β for example, reading a header line, then streaming the rest differently.
Read bytes
byte[] bytes = Files.readAllBytes(Path.of("image.png"));
// Same size-warning as readAllLines
For stream-based byte reading:
try (InputStream in = Files.newInputStream(Path.of("image.png"))) {
byte[] buffer = new byte[8192];
int n;
while ((n = in.read(buffer)) != -1) {
// process n bytes
}
}
Charset control
Don't rely on the platform default β be explicit:
import java.nio.charset.StandardCharsets;
String c = Files.readString(Path.of("data.txt"), StandardCharsets.ISO_8859_1);
List<String> l = Files.readAllLines(Path.of("data.txt"), StandardCharsets.UTF_8);
Common charsets: UTF_8 (default), ISO_8859_1 (Latin-1), UTF_16. Pass them via StandardCharsets to avoid typos.
Error handling
import java.io.IOException;
import java.nio.file.NoSuchFileException;
try {
String c = Files.readString(Path.of("missing.txt"));
} catch (NoSuchFileException e) {
System.err.println("Not found: " + e.getFile());
} catch (IOException e) {
System.err.println("I/O error: " + e.getMessage());
}
Always catch the most specific subclass you can β NoSuchFileException, AccessDeniedException, MalformedInputException β before falling back to generic IOException.
Reading from the classpath (resource files)
For files bundled inside your JAR (e.g. src/main/resources/config.json):
try (InputStream in = getClass().getResourceAsStream("/config.json")) {
if (in == null) throw new IllegalStateException("Missing resource");
String content = new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
Note the leading / β classpath paths are absolute relative to the resources root.
Parsing common formats
CSV
split(",") doesn't handle quoted fields, commas in values, or multiline entries. Use a library:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.18.2</version>
</dependency>
JSON
ObjectMapper mapper = new ObjectMapper();
Config cfg = mapper.readValue(Path.of("config.json").toFile(), Config.class);
Properties
Properties p = new Properties();
try (Reader r = Files.newBufferedReader(Path.of("app.properties"))) {
p.load(r);
}
String port = p.getProperty("server.port", "8080");
Which method for which situation?
| File size | Structure | Recommended |
|---|---|---|
| Small (< 10 MB) | Single blob (JSON, XML, config) | Files.readString |
| Small | Line-based | Files.readAllLines |
| Large (> 100 MB) | Line-based | Files.lines in try-with-resources |
| Binary | Small | Files.readAllBytes |
| Binary | Large | Files.newInputStream with buffered read |
| Classpath resource | Any | getResourceAsStream |
Common mistakes
- Not closing streams:
Files.linesandnewBufferedReadermust be closed via try-with-resources. - Using platform default charset: causes bugs when code moves between systems.
- Reading a huge log file with
readAllLines: OutOfMemoryError waiting to happen. - Forgetting that
Paths.get(older API) andPath.of(Java 11+) do the same thing; prefer the newer.
For everyday file reading in modern Java, Files.readString and Files.lines cover nearly every real-world need in a single line, with explicit charset control and proper resource handling.