0

[Java Backend Zero to Hello] [Phase 2] BÀI 2.8: I/O & FILE

📚 Series: Java Backend Zero to Hello 📂 Phân đoạn: Phase 2: Java Core nâng cao 📖 Nội dung: BÀI 2.8: I/O & FILE 💡 Khóa học lập trình Backend Java & Spring Boot chuẩn doanh nghiệp từ con số 0.


BÀI 2.8: I/O & FILE

Mục tiêu

  • Đọc/ghi file với Java I/O
  • Sử dụng NIO.2 (Java 7+)
  • Thao tác với Path và Files
  • Serialization

1. HỆ THỐNG I/O

1.1 java.io (Cổ điển)

  • Stream-based
  • Blocking I/O
  • Phù hợp với file nhỏ

1.2 java.nio (New I/O)

  • Buffer-based
  • Non-blocking I/O
  • Hiệu năng cao hơn

1.3 java.nio.file (NIO.2 - Java 7+)

  • API hiện đại cho file
  • Hỗ trợ filesystem operations

2. JAVA.IO CƠ BẢN

2.1 Byte Stream

Đọc/ghi dữ liệu nhị phân.

import java.io.*;

// Đọc file
try (FileInputStream fis = new FileInputStream("data.bin");
     BufferedInputStream bis = new BufferedInputStream(fis)) {

    int byteData;
    while ((byteData = bis.read()) != -1) {
        System.out.print((char) byteData);
    }
}

// Ghi file
try (FileOutputStream fos = new FileOutputStream("output.bin");
     BufferedOutputStream bos = new BufferedOutputStream(fos)) {

    String data = "Hello World";
    bos.write(data.getBytes());
}

2.2 Character Stream

Đọc/ghi văn bản (tự xử lý encoding).

// Đọc file text
try (FileReader fr = new FileReader("data.txt");
     BufferedReader br = new BufferedReader(fr)) {

    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

// Ghi file text
try (FileWriter fw = new FileWriter("output.txt");
     BufferedWriter bw = new BufferedWriter(fw)) {

    bw.write("Hello World");
    bw.newLine();
    bw.write("Dòng 2");
}

2.3 PrintWriter

try (PrintWriter pw = new PrintWriter(new FileWriter("output.txt"))) {
    pw.println("Hello");
    pw.printf("Tuổi: %d%n", 25);
    pw.printf("Tên: %s%n", "An");
}

3. NIO.2 (JAVA 7+)

3.1 Path

import java.nio.file.Path;
import java.nio.file.Paths;

Path path1 = Paths.get("data.txt");
Path path2 = Paths.get("C:", "Users", "Admin", "data.txt");
Path path3 = Paths.get("C:\\Users\\Admin\\data.txt");

// Thông tin
path1.getFileName();      // data.txt
path1.getParent();        // null (file ở root)
path1.getRoot();          // null
path1.toAbsolutePath();   // Đường dẫn tuyệt đối
path1.toString();         // data.txt

3.2 Files - Đọc/Ghi

import java.nio.file.Files;
import java.nio.file.StandardOpenOption;

// Đọc tất cả
byte[] bytes = Files.readAllBytes(Paths.get("data.bin"));
List<String> lines = Files.readAllLines(Paths.get("data.txt"));
String content = Files.readString(Paths.get("data.txt"));  // Java 11+

// Ghi
Files.write(Paths.get("output.txt"), "Hello".getBytes());
Files.write(Paths.get("output.txt"), lines);
Files.writeString(Paths.get("output.txt"), "Hello World");  // Java 11+

// Append
Files.write(Paths.get("log.txt"), "New line\n".getBytes(),
    StandardOpenOption.APPEND);

3.3 Files - Thao tác

// Copy
Files.copy(Paths.get("source.txt"), Paths.get("dest.txt"),
    StandardCopyOption.REPLACE_EXISTING);

// Move
Files.move(Paths.get("source.txt"), Paths.get("dest.txt"),
    StandardCopyOption.REPLACE_EXISTING);

// Delete
Files.delete(Paths.get("file.txt"));        // Ném exception nếu không tồn tại
Files.deleteIfExists(Paths.get("file.txt")); // Không ném exception

// Tạo
Files.createFile(Paths.get("new.txt"));
Files.createDirectory(Paths.get("newdir"));
Files.createDirectories(Paths.get("a/b/c"));  // Tạo cả cây thư mục

// Thông tin
boolean exists = Files.exists(Paths.get("file.txt"));
boolean isDir = Files.isDirectory(Paths.get("dir"));
long size = Files.size(Paths.get("file.txt"));
FileTime lastModified = Files.getLastModifiedTime(Paths.get("file.txt"));

3.4 Directory Stream

try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get("."))) {
    for (Path entry : stream) {
        System.out.println(entry.getFileName());
    }
}

// Filter
try (DirectoryStream<Path> stream = Files.newDirectoryStream(
        Paths.get("."), "*.txt")) {
    for (Path entry : stream) {
        System.out.println(entry.getFileName());
    }
}

3.5 Walk - Duyệt cây thư mục

// Duyệt tất cả file
Stream<Path> walk = Files.walk(Paths.get("."));
walk.filter(Files::isRegularFile)
    .forEach(System.out::println);

// Tìm file
try (Stream<Path> walk = Files.walk(Paths.get("."))) {
    List<Path> javaFiles = walk
        .filter(p -> p.toString().endsWith(".java"))
        .collect(Collectors.toList());
}

4. SERIALIZATION

Chuyển object thành byte stream để lưu trữ hoặc truyền qua mạng.

4.1 Serializable

import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;
    private transient String password;  // Không serialize

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

4.2 Serialize

User user = new User("An", 25);

try (ObjectOutputStream oos = new ObjectOutputStream(
        new FileOutputStream("user.ser"))) {
    oos.writeObject(user);
}

4.3 Deserialize

try (ObjectInputStream ois = new ObjectInputStream(
        new FileInputStream("user.ser"))) {
    User user = (User) ois.readObject();
    System.out.println(user.getName());
}

5. ĐỌC/GHI CSV

// Đọc CSV
List<String[]> data = Files.readAllLines(Paths.get("data.csv"))
    .stream()
    .map(line -> line.split(","))
    .collect(Collectors.toList());

// Ghi CSV
List<String> lines = users.stream()
    .map(u -> u.getId() + "," + u.getName() + "," + u.getEmail())
    .collect(Collectors.toList());
Files.write(Paths.get("users.csv"), lines);

6. ĐỌC/GHI JSON (với thư viện)

Trong thực tế, dùng Jackson hoặc Gson:

// Với Jackson
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(new File("user.json"), User.class);
mapper.writeValue(new File("user.json"), user);

7. BÀI TẬP THỰC HÀNH

Bài 1: Đọc file log

public List<String> readLogFile(String path) throws IOException {
    return Files.readAllLines(Paths.get(path));
}

public List<String> filterErrors(String path) throws IOException {
    return Files.lines(Paths.get(path))
        .filter(line -> line.contains("ERROR"))
        .collect(Collectors.toList());
}

Bài 2: Copy thư mục

public void copyDirectory(Path source, Path target) throws IOException {
    Files.walk(source).forEach(src -> {
        Path dest = target.resolve(source.relativize(src));
        try {
            Files.copy(src, dest, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    });
}

Bài 3: Tìm file lớn nhất

public Optional<Path> findLargestFile(Path dir) throws IOException {
    try (Stream<Path> walk = Files.walk(dir)) {
        return walk
            .filter(Files::isRegularFile)
            .max(Comparator.comparingLong(p -> {
                try {
                    return Files.size(p);
                } catch (IOException e) {
                    return 0L;
                }
            }));
    }
}

Bài 4: Word count

public Map<String, Long> wordCount(Path file) throws IOException {
    return Files.lines(file)
        .flatMap(line -> Arrays.stream(line.split("\\s+")))
        .collect(Collectors.groupingBy(
            String::toLowerCase,
            Collectors.counting()
        ));
}

8. TÓM TẮT

API Mô tả
FileInputStream / FileOutputStream Byte stream
FileReader / FileWriter Character stream
BufferedReader / BufferedWriter Buffered (hiệu quả hơn)
Path / Paths Đường dẫn (NIO.2)
Files Thao tác file (NIO.2)
Serializable Tuần tự hóa object
ObjectInputStream / ObjectOutputStream Serialize/Deserialize

Bài tiếp theo: 2.9 Annotation & Reflection


🧭 Điều hướng bài học

⭐ Hãy bookmark (clip) lại series để tiện theo dõi các bài học tiếp theo nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí