File I/O with java.nio.file

আধুনিক Java ফাইল I/O — Path, Files এবং streaming

Read: ~25 min Intermediate 5 practice problems Live code runner

1. The Modern Way — java.nio.file

For two decades Java developers fought with java.io.File — a clumsy, platform-confused API with almost no error reporting. Java 7 introduced java.nio.file (the "NIO.2" API) to fix all of that. It gives you Path for filesystem locations, Files for operations, and built-in support for streaming gigabyte-sized files without loading them into memory.

বহু বছর Java-র পুরনো java.io.File API অসুবিধাজনক ছিল — platform-এর দ্বিধাগ্রস্ত, error reporting খারাপ। Java 7 থেকে java.nio.file এসেছে। এখানে Path দিয়ে ফাইল-লোকেশন, Files দিয়ে operation, এবং GB-সাইজ ফাইলও memory-তে না এনে stream হিসেবে process করা যায়। নতুন কোডে সবসময় এই নতুন API ব্যবহার করুন।

The three pillars: Path (a location), Files (static operations), and streams / readers for large files. Nearly every real Java backend — Spring Boot, Kafka, Elasticsearch — uses java.nio.file under the hood.

2. Path, Files, and the Flow

A Path is just a reference to a file or directory — it does not mean the file exists yet. You build one with Path.of("..."). Then Files gives you a huge static API: readString, writeString, lines, exists, copy, move, delete, walk, and many more.

Path হলো শুধু একটি reference — ফাইল আছে কিনা সেটা বলে না। Path.of("...") দিয়ে তৈরি করুন। তারপর Files-এর static method দিয়ে read, write, copy, move, delete সব operation করুন। এই দুটি class-ই ৯৫% সময় যথেষ্ট।
java.nio.file — the modern I/O shape Path.of("data.txt") a location (lazy) Files.readString(path) eager — whole file in RAM String content ready to use Files.lines(path) lazy Stream<String> .filter().map().forEach() one line at a time GB-sized file OK constant memory Figure 32.1 — ছোট ফাইলে readString, বড় ফাইলে Files.lines।

3. Write and Read a Text File

The simplest round-trip: write a few lines with Files.writeString, read them back with Files.readString. Everything throws IOException, so main declares throws Exception.

সবচেয়ে সহজ flow — Files.writeString দিয়ে লিখুন, Files.readString দিয়ে পড়ুন। I/O operation-এ IOException হতে পারে, তাই main-এ throws Exception দিয়ে দিন।
Main.java
import java.nio.file.*;

class Main {
    public static void main(String[] args) throws Exception {
        Path path = Path.of("notes.txt");

        // 1) write
        Files.writeString(path, "Hello Bangladesh\nABCL TECH\nJava 21\n");

        // 2) read it back
        String text = Files.readString(path);
        System.out.println("--- file content ---");
        System.out.print(text);

        // 3) metadata
        System.out.println("size = " + Files.size(path) + " bytes");
        System.out.println("exists = " + Files.exists(path));
    }
}

4. Streaming Large Files with Files.lines

Files.readAllLines loads the whole file into a List<String> — fine for a config file, a disaster for a 5 GB log. Files.lines returns a Stream<String> that reads one line at a time. Always close it with try-with-resources.

Files.readAllLines পুরো ফাইল memory-তে আনে — ছোট config ঠিক আছে, কিন্তু ৫ GB log হলে OutOfMemoryError। Files.lines lazy stream দেয় — একবারে একটি line পড়ে। সবসময় try-with-resources দিয়ে বন্ধ করুন।
Main.java
import java.nio.file.*;
import java.util.stream.*;

class Main {
    public static void main(String[] args) throws Exception {
        Path p = Path.of("log.txt");
        Files.writeString(p,
            "INFO  starting\nERROR disk full\nINFO  retry\nERROR timeout\nINFO  ok\n");

        // count only ERROR lines — without loading the whole file
        long errors;
        try (Stream<String> lines = Files.lines(p)) {
            errors = lines.filter(l -> l.startsWith("ERROR")).count();
        }
        System.out.println("error lines: " + errors);
    }
}
Rule of thumb: file < 10 MB → readString. File > 10 MB → Files.lines in try-with-resources. Never call readAllLines on something you did not write yourself.

5. BufferedReader for Fine Control

Sometimes you need more than a stream — you want to read header lines separately, or you need a specific charset. Files.newBufferedReader gives you a BufferedReader that plays nicely with try-with-resources and defaults to UTF-8.

কখনো কখনো header আলাদা পড়তে হয়, বা নির্দিষ্ট charset দরকার। তখন Files.newBufferedReader ব্যবহার করুন — try-with-resources-এ কাজ করে এবং default-এ UTF-8।
Main.java
import java.io.*;
import java.nio.file.*;

class Main {
    public static void main(String[] args) throws Exception {
        Path p = Path.of("users.csv");
        Files.writeString(p, "name,age\nRaihan,24\nNusrat,22\nTariq,30\n");

        try (BufferedReader br = Files.newBufferedReader(p)) {
            String header = br.readLine();
            System.out.println("header: " + header);

            String line;
            while ((line = br.readLine()) != null) {
                String[] cols = line.split(",");
                System.out.println(cols[0] + " is " + cols[1]);
            }
        }
    }
}

6. Binary I/O, Copy, and Delete

For binary data use Files.readAllBytes / Files.write(path, bytes). For filesystem management use Files.copy, Files.move, Files.delete, and their -IfExists variants. The StandardCopyOption.REPLACE_EXISTING flag is your friend.

Binary data-র জন্য readAllBytes / write(path, bytes)। ফাইল-সিস্টেম management-এ copy, move, delete এবং তাদের -IfExists সংস্করণ। একই নামের ফাইল থাকলে overwrite করতে REPLACE_EXISTING flag দিন।
Cheat sheet
TaskAPIবাংলায়
Build a pathPath.of("dir", "file.txt")location তৈরি
Read small textFiles.readString(p)ছোট ফাইল পড়া
Write textFiles.writeString(p, s)ফাইল-এ লেখা
Append textFiles.writeString(p, s, APPEND)শেষে যোগ
Stream linesFiles.lines(p)বড় ফাইল stream
Binary readFiles.readAllBytes(p)raw bytes
Exists / sizeFiles.exists, Files.sizemetadata
CopyFiles.copy(src, dst, REPLACE_EXISTING)কপি
DeleteFiles.deleteIfExists(p)থাকলে মুছবে
List dirFiles.list(dir)ডিরেক্টরির ফাইল
Main.java
import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*;

class Main {
    public static void main(String[] args) throws Exception {
        Path a = Path.of("a.txt");
        Path b = Path.of("b.txt");

        Files.writeString(a, "original");
        Files.copy(a, b, REPLACE_EXISTING);
        System.out.println("b says: " + Files.readString(b));

        boolean removed = Files.deleteIfExists(b);
        System.out.println("deleted b: " + removed);
    }
}

7. Vocabulary

TermMeaningবাংলায়
PathAn abstract location — file or directory.ফাইল বা ডিরেক্টরির location।
FilesStatic utility class for all common I/O operations.I/O operation-এর static utility class।
CharsetEncoding used to turn bytes into characters (UTF-8 by default).byte → character encoding (default UTF-8)।
BufferedReaderA reader that reads chunks efficiently for line-by-line access.line-by-line পড়ার efficient reader।
Stream<String>Lazy sequence of lines — processed one by one.lazy line sequence — একবারে একটি line।
IOExceptionChecked exception thrown by almost every I/O call.I/O call-এর checked exception।

8. Practice Problems

Try each problem yourself, then open the answer.

প্রতিটি প্রশ্ন আগে নিজে চেষ্টা করুন, তারপর উত্তর দেখুন।
  1. Write "Hello, I/O" to hello.txt, read it back, and print it.
    hello.txt-এ "Hello, I/O" লিখে আবার পড়ে print করুন।
    Show Answer (উত্তর দেখুন)
    Main.java
    import java.nio.file.*;
    class Main {
        public static void main(String[] args) throws Exception {
            Path p = Path.of("hello.txt");
            Files.writeString(p, "Hello, I/O");
            System.out.println(Files.readString(p));
        }
    }
  2. Count the number of lines in a multi-line file using Files.lines.
    Files.lines দিয়ে একটি multi-line ফাইলের line সংখ্যা গুনুন।
    Show Answer (উত্তর দেখুন)
    Main.java
    import java.nio.file.*;
    import java.util.stream.*;
    class Main {
        public static void main(String[] args) throws Exception {
            Path p = Path.of("poem.txt");
            Files.writeString(p, "one\ntwo\nthree\nfour\n");
            try (Stream<String> s = Files.lines(p)) {
                System.out.println("lines = " + s.count());
            }
        }
    }
  3. Append a log message to an existing file without overwriting it.
    overwrite না করে একটি বিদ্যমান ফাইলে log বার্তা append করুন।
    Show Answer (উত্তর দেখুন)
    Main.java
    import java.nio.file.*;
    import static java.nio.file.StandardOpenOption.*;
    class Main {
        public static void main(String[] args) throws Exception {
            Path p = Path.of("app.log");
            Files.writeString(p, "startup\n");
            Files.writeString(p, "shutdown\n", APPEND);
            System.out.print(Files.readString(p));
        }
    }
  4. Explain in 2–3 sentences why Files.lines must be used inside try-with-resources.
    দুই-তিন বাক্যে ব্যাখ্যা করুন — Files.lines কেন try-with-resources-এ ব্যবহার করতে হয়।
    Show Answer (উত্তর দেখুন)

    Answer: Files.lines keeps an open file handle behind the lazy stream. If the stream is not closed, the OS file descriptor leaks — and on long-running servers that eventually hits the file-descriptor limit. Try-with-resources guarantees the stream (and its underlying reader) is closed whether iteration finishes normally or throws.

    Files.lines-এর lazy stream-এর পেছনে একটি খোলা ফাইল handle থাকে। stream বন্ধ না হলে OS file descriptor leak হয় — বড় server-এ এতে limit exceed হয়ে crash হয়। try-with-resources নিশ্চিত করে — iteration শেষ হোক বা exception হোক, stream বন্ধ হবেই।

  5. Create a text file with 5 names, then print only names that start with 'R'.
    ৫টি নাম লেখা একটি ফাইল বানান, তারপর শুধু 'R' দিয়ে শুরু হওয়া নামগুলো print করুন।
    Show Answer (উত্তর দেখুন)
    Main.java
    import java.nio.file.*;
    import java.util.stream.*;
    class Main {
        public static void main(String[] args) throws Exception {
            Path p = Path.of("names.txt");
            Files.writeString(p, "Raihan\nNusrat\nRafi\nTariq\nRina\n");
            try (Stream<String> s = Files.lines(p)) {
                s.filter(n -> n.startsWith("R")).forEach(System.out::println);
            }
        }
    }

Summary — Module 32

Modern Java I/O lives in java.nio.file. Build locations with Path.of, operate with the static methods on Files, and stream huge files with Files.lines inside try-with-resources. Use readString / writeString for small text, readAllBytes for binary, and always let I/O exceptions propagate to a sensible boundary instead of swallowing them.

আধুনিক Java I/O-র ভিত্তি java.nio.file। Path.of দিয়ে location তৈরি করুন, Files-এর static method দিয়ে কাজ করুন, বড় ফাইল Files.lines stream দিয়ে try-with-resources-এ পড়ুন। ছোট text-এ readString/writeString, binary-তে readAllBytes।

Next Module → JSON & Serialization — Jackson ও Gson দিয়ে Java object ↔ JSON।