Java NIO (New Input/Output) API

java.nio Package 🆕

java.nio is the New I/O API introduced in Java 1.4 to provide a more scalable I/O operations model. It includes support for buffer-oriented and channel-based I/O operations.

Why Java NIO 🤔

  • How to work with paths in a platform-independent way?
  • How to perform file operations more efficiently?
  • How to handle large files without loading them entirely into memory?
  • How to prevent multiple processes from modifying the same file simultaneously?

Key Differences from java.io 📝

Featurejava.iojava.nio
ProcessingStream orientedBuffer oriented
OperationsBlockingNon-blocking capable
Buffer handlingNo built-in buffer supportBuilt-in buffer support
Channel supportNo channel conceptChannel based
File lockingLimited supportFull support

Note: Choose NIO when you need non-blocking operations, memory mapping for large files, or file locking capabilities. Use traditional I/O when you need simpler, stream-based operations.

Working with Paths 🛣️

The Path interface, part of the java.nio.file, represents a file system path in an OS-neutral way. To create a Path instance, use the Paths.get() method:

1
2
3
4
5
6
import java.nio.file.*;

// Creating paths
Path path1 = Paths.get("file.txt");                    // Current directory
Path path2 = Paths.get("/home/user/docs/file.txt");    // Absolute path
Path path3 = Paths.get("docs", "files", "file.txt");   // Join paths

File Operations with Files Class 📂

The Files class, part of the java.nio.file package, provides static methods for file and directory operations.

Creating Files and Directories

  • To create a new file, use the Files.createFile() method.
  • To create a new directory, use the Files.createDirectory() method.
  • To create multiple directories, use the Files.createDirectories() method.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import java.nio.file.*;

public class FileOperations {
    public void createFiles() throws IOException {
        // Create a file
        Path file = Files.createFile(Paths.get("example.txt"));
        
        // Create a directory
        Path dir = Files.createDirectory(Paths.get("docs"));
        
        // Create multiple directories
        Path dirs = Files.createDirectories(Paths.get("docs/2024/feb"));
    }
}

Reading and Writing Files

  • To read the content of a file, use the Files.readAllLines() method.
  • To write content to a file, use the Files.write() method.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import java.nio.file.*;
import java.util.List;

public class FileReadWrite {
    public void readWrite() throws IOException {
        Path file = Paths.get("example.txt");
        
        // Write all lines at once
        List<String> lines = Arrays.asList("Line 1", "Line 2");
        Files.write(file, lines);
        
        // Read all lines at once
        List<String> readLines = Files.readAllLines(file);
        
        // Stream lines for large files
        try (Stream<String> stream = Files.lines(file)) {
            stream.forEach(System.out::println);
        }
    }
}

Copy, Move, and Delete Operations

  • To copy a file, use the Files.copy() method.
  • To move or rename a file, use the Files.move() method.
  • To delete a file, use the Files.delete() method.
  • To safely delete a file, use the Files.deleteIfExists() method.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import java.nio.file.*;

public class FileCopyMove {
    public void copyMoveDelete() throws IOException {
        // Copy file
        Path source = Paths.get("source.txt");
        Path target = Paths.get("target.txt");
        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
        
        // Move/Rename file
        Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);
        
        // Delete file
        Files.delete(target);
        // or safely delete
        Files.deleteIfExists(target);
    }
}

Memory-Mapped Files 📝 🗄️

Memory-mapped files allow you to map a file directly into memory for faster access to file content. This is especially useful for processing large files that can’t fit into memory all at once. With memory-mapped files, you can efficiently access and modify file content without loading the entire file into memory.

Creating a Memory-mapped File

To create a memory-mapped file, use the FileChannel.map() method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.*;

public class MemoryMappedExample {
    public void mapFile() throws IOException {
        Path path = Paths.get("large-file.dat");
        try (FileChannel channel = FileChannel.open(path, 
                StandardOpenOption.READ, StandardOpenOption.WRITE)) {
            
            // Map the file into memory
            MappedByteBuffer buffer = channel.map(
                FileChannel.MapMode.READ_WRITE, 0, channel.size());
            
            // Read/Write directly in memory
            while (buffer.hasRemaining()) {
                byte b = buffer.get();  // Read a byte
                buffer.put((byte)(b + 1));  // Write a modified byte
            }
        }
    }
}

File Locking 🔒

File locking prevents multiple processes from accessing the same file simultaneously. There are two type of file locks:

  • Exclusive Lock: An exclusive lock prevents other processes from accessing the locked region of the file.
  • Shared Lock: A shared lock allows multiple processes to read from the locked region of the file but prevents writing.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.nio.channels.*;
import java.nio.file.*;

public class FileLockExample {
    public void lockFile() throws IOException {
        Path path = Paths.get("shared-file.txt");
        try (FileChannel channel = FileChannel.open(path, 
                StandardOpenOption.READ, StandardOpenOption.WRITE)) {
            
            // Exclusive lock (no other process can read or write)
            FileLock exclusiveLock = channel.lock();
            try {
                // Work with file...
            } finally {
                exclusiveLock.release();
            }
            
            // Shared lock (other processes can read but not write)
            FileLock sharedLock = channel.lock(0, Long.MAX_VALUE, true);
            try {
                // Work with file...
            } finally {
                sharedLock.release();
            }
        }
    }
}