Xử lý luồng byte trong Java

Trong lập trình Java, luồng byte (byte stream) là cơ chế nền tảng để thao tác với dữ liệu nhị phân, bao gồm cả văn bản và tài nguyên đa phương tiện như ảnh, video. Các lớp chính thuộc nhóm này được định nghĩa trong gói java.io, với hai lớp cốt lõi là FileInputStreamFileOutputStream.

Các phương thức ghi dữ liệu bằng luồng byte

Luồng đầu ra byte hỗ trợ ba cách phổ biến để ghi dữ liệu:

  • Ghi từng byte riêng lẻ: sử dụng write(int b) — chỉ ghi byte thấp nhất của giá trị truyền vào.
  • Ghi toàn bộ mảng byte: dùng write(byte[] b) để ghi toàn bộ nội dung mảng.
  • Ghi một phần mảng: thông qua write(byte[] b, int off, int len), cho phép chỉ định vị trí bắt đầu và độ dài cần ghi.

Ví dụ minh họa:

import java.io.*;

public class ByteStreamWriter {
    public static void main(String[] args) throws IOException {
        try (FileOutputStream output = new FileOutputStream("data/output.bin")) {
            // Cách 1: Ghi từng ký tự ASCII
            output.write('J');
            output.write('a');
            output.write('v');
            output.write('a');

            // Cách 2: Ghi chuỗi dưới dạng mảng byte
            byte[] content = " - Hello World".getBytes(StandardCharsets.UTF_8);
            output.write(content);

            // Cách 3: Chỉ ghi phần con "World" từ mảng trên
            output.write(content, 11, 5); // offset=11, length=5
        }
    }
}

Thêm dòng mới và ghi nối tiếp

Để xuống dòng khi ghi, chèn byte tương ứng với ký tự xuống dòng của hệ điều hành: \n (LF, Unix/Linux/macOS) hoặc \r\n (CRLF, Windows). Để ghi nối tiếp (append), khởi tạo FileOutputStream với tham số thứ hai là true:

FileOutputStream appendStream = new FileOutputStream("log.txt", true);

Xử lý ngoại lệ an toàn

Nên sử dụng khối try-with-resources để đảm bảo đóng luồng tự động, tránh rò rỉ tài nguyên — đặc biệt quan trọng khi làm việc với tệp lớn hoặc trong môi trường sản xuất.

Đọc dữ liệu từ luồng byte

Hai kỹ thuật phổ biến:

  • Đọc từng byte: gọi read(), trả về giá trị int từ 0 đến 255, hoặc -1 nếu hết dữ liệu.
  • Đọc theo khối: dùng read(byte[] b) hoặc read(byte[] b, int off, int len) để tăng hiệu suất đáng kể.

Sao chép tệp nhị phân

Do luồng byte không phụ thuộc vào mã hóa, chúng phù hợp để sao chép mọi loại tệp — từ văn bản thuần đến ảnh JPEG, video MP4 hay file nén ZIP. Mẫu thiết kế chuẩn là đọc từng khối (ví dụ: 8192 byte) và ghi ngay lập tức vào đích.

Hiệu năng với luồng đệm

Để tối ưu tốc độ I/O, nên bao bọc luồng cơ sở bằng BufferedInputStreamBufferedOutputStream. Các lớp này duy trì vùng đệm trong bộ nhớ giúp giảm số lần truy cập đĩa.

import java.io.*;
import java.nio.charset.StandardCharsets;

public class BufferedCopyExample {
    public static void main(String[] args) throws IOException {
        // Ghi có đệm
        try (BufferedOutputStream bufferedOut = new BufferedOutputStream(
                new FileOutputStream("buffered.txt"))) {
            bufferedOut.write("Dòng đầu tiên".getBytes(StandardCharsets.UTF_8));
            bufferedOut.write("\n".getBytes());
            bufferedOut.write("Dòng thứ hai".getBytes(StandardCharsets.UTF_8));
        }

        // Đọc có đệm
        try (BufferedInputStream bufferedIn = new BufferedInputStream(
                new FileInputStream("buffered.txt"))) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = bufferedIn.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8));
            }
        }
    }
}

Thẻ: java-io byte-stream file-input-output buffered-stream

Đăng vào ngày 17 tháng 05 lúc 18:03