← All articles
Backend1 min read

Java IO vs NIO

Classic streams are simple and blocking; NIO adds channels, buffers, and non-blocking I/O. Knowing when to use each keeps your file and network code efficient.

S

Swapnika Voora

Author

The original java.io package models data as blocking streams of bytes. java.nio adds buffers, channels, and the modern Path API, along with non-blocking modes for scalable network servers.

The modern file API

For most file work, java.nio.file.Files is the cleanest option — no manual stream closing, no boilerplate.

Files.java
Path path = Path.of("data", "report.csv");
List<String> lines = Files.readAllLines(path);
Files.writeString(path, "done\n", StandardOpenOption.APPEND);
 
try (var stream = Files.lines(path)) {      // lazy, for large files
    long count = stream.filter(l -> l.contains("ERROR")).count();
}

Buffers and channels

Channels read into reusable buffers, avoiding per-read allocation for high-throughput I/O.

Channel.java
try (var channel = FileChannel.open(path)) {
    ByteBuffer buffer = ByteBuffer.allocate(8192);
    while (channel.read(buffer) > 0) {
        buffer.flip();
        process(buffer);
        buffer.clear();
    }
}

Takeaways

  • Use Files helpers for everyday file reads and writes.
  • Stream large files lazily with Files.lines inside try-with-resources.
  • Reserve raw channels and buffers for performance-critical paths.

Always close Files.lines streams — they hold an open file handle until the stream is closed.

#java#io#nio

More in Backend