Luồng Dữ liệu
(Data Streams)

Data Streams là một phần quan trọng trong Java I/O, hỗ trợ thao tác với dữ liệu nhị phân cho các kiểu dữ liệu nguyên thủy như boolean, char, byte, short, int, long, float, double và cả kiểu dữ liệu String. Chúng cho phép bạn đọc và ghi dữ liệu dưới dạng nhị phân một cách hiệu quả, phù hợp cho việc lưu trữ hoặc truyền dữ liệu giữa các ứng dụng hoặc qua mạng.

Data Streams hoạt động dựa trên hai giao diện chính là DataInput và DataOutput. Các giao diện này định nghĩa các phương thức cần thiết để đọc và ghi dữ liệu nguyên thủy. Hai lớp triển khai phổ biến nhất của các giao diện này là DataInputStream và DataOutputStream.

↳ DataInputStream: Được sử dụng để đọc dữ liệu nhị phân từ một nguồn như file hoặc mạng.

↳ DataOutputStream: Được sử dụng để ghi dữ liệu nhị phân vào một đích như file hoặc mạng.

Sử dụng Data Streams trong Java giúp bạn lưu trữ và khôi phục dữ liệu một cách dễ dàng và an toàn, đặc biệt hữu ích trong các ứng dụng cần xử lý khối lượng lớn dữ liệu hoặc yêu cầu truyền tải dữ liệu chính xác giữa các hệ thống.

Ví dụ về DataStreams

Ví dụ này minh họa cách sử dụng Data Streams bằng cách ghi ra một tập hợp các bản ghi dữ liệu và sau đó đọc lại chúng. Mỗi bản ghi bao gồm ba giá trị liên quan đến một mục trên hóa đơn, được mô tả trong bảng dưới đây:

Thứ tự trong bản ghiKiểu dữ liệuMô tả dữ liệuPhương thức OutputPhương thức InputGiá trị mẫu
1doubleGiá của sản phẩmDataOutputStream.writeDoubleDataInputStream.readDouble19.99
2intSố lượng đơn vịDataOutputStream.writeIntDataInputStream.readInt12
3StringMô tả sản phẩmDataOutputStream.writeUTFDataInputStream.readUTF"Java T-Shirt"

Bây giờ chúng ta sẽ khám phá chi tiết từng lớp trong luồng dữ liệu trong Java, bao gồm các lớp chính được sử dụng để thực hiện các hoạt động đầu vào và đầu ra liên quan đến dữ liệu.

Lớp DataInputStream (Class DataInputStream)

DataInputStream là một lớp con của FilterInputStream và triển khai giao diện DataInput. Lớp này cho phép một ứng dụng đọc các kiểu dữ liệu nguyên thủy như boolean, char, byte, short, int, long, float, double và chuỗi theo định dạng UTF-8 của Java từ một luồng đầu vào cơ bản theo cách độc lập với máy tính. Một ứng dụng có thể sử dụng DataOutputStream để ghi dữ liệu, sau đó dữ liệu này có thể được đọc lại bởi DataInputStream.

Một điểm cần lưu ý là DataInputStream không đảm bảo an toàn trong môi trường đa luồng. Việc đảm bảo tính an toàn cho luồng là tùy chọn và thuộc trách nhiệm của người dùng khi sử dụng các phương thức trong lớp này.

Khai báo lớp DataInputStream trong Java

Để sử dụng lớp DataInputStream, bạn cần import gói java.io bạn cần thêm câu lệnh import vào đầu file Java của mình. Gói này cung cấp các lớp và giao diện để thực hiện các hoạt động nhập xuất (I/O) trong Java.

Cú pháp câu lệnh import:

Cú pháp

import java.io.DataInputStream;

Cú pháp khai báo lớp DataInputStream:

Cú pháp

public class DataInputStream
extends FilterInputStream
implements DataInput

Dưới đây là giải thích chi tiết về cú pháp khai báo này:

↳ public class DataInputStream: Đây là khai báo một lớp công khai (public) tên là DataInputStream. Lớp này có thể được truy cập từ bất kỳ đâu trong dự án Java, miễn là nó được import hoặc ở cùng gói.

↳ extends FilterInputStream: DataInputStream kế thừa từ FilterInputStream. FilterInputStream là một lớp cơ sở trong Java cung cấp khả năng lọc cho các luồng đầu vào. Lớp này cho phép bạn "bọc" một InputStream khác và thêm các chức năng mới hoặc thay đổi hành vi của luồng đó. Khi kế thừa từ FilterInputStream, DataInputStream có thể sử dụng hoặc mở rộng các tính năng của FilterInputStream, chẳng hạn như các phương thức cơ bản để đọc dữ liệu byte từ luồng.

↳ implements DataInput: DataInputStream thực hiện giao diện DataInput. DataInput là một giao diện trong Java cung cấp các phương thức để đọc các kiểu dữ liệu nguyên thủy từ một luồng đầu vào, chẳng hạn như int, float, double, long, và UTF strings.

Việc thực hiện giao diện DataInput cho phép DataInputStream cung cấp các phương thức để đọc các kiểu dữ liệu này từ luồng đầu vào một cách chính xác và thuận tiện.

Constructor của lớp DataInputStream

Lớp DataInputStream chỉ có một constructor:

↳ DataInputStream(InputStream in): Tạo một đối tượng DataInputStream sử dụng luồng đầu vào cơ bản InputStream đã chỉ định. Lưu trữ tham chiếu đến InputStream để sử dụng trong các phương thức đọc dữ liệu.

Các phương thức của lớp DataInputStream

Lớp DataInputStream cung cấp các phương thức để đọc các kiểu dữ liệu nguyên thủy từ luồng đầu vào cơ bản. Dưới đây là danh sách tất cả các phương thức của lớp DataInputStream trong Java:

↳ int read(byte[] b): Đọc một số byte từ luồng đầu vào và lưu vào mảng byte b.

↳ int read(byte[] b, int off, int len): Đọc tối đa len byte từ luồng đầu vào vào mảng byte b bắt đầu từ vị trí off.

↳ boolean readBoolean(): Đọc một giá trị boolean từ luồng.

↳ byte readByte(): Đọc một byte 8 bit từ luồng.

↳ char readChar(): Đọc một ký tự 16 bit từ luồng.

↳ double readDouble(): Đọc một số thực 64 bit từ luồng.

↳ float readFloat(): Đọc một số thực 32 bit từ luồng.

↳ void readFully(byte[] b): Đọc đầy đủ mảng byte từ luồng, chặn cho đến khi đọc xong.

↳ String readLine(): Phương thức này đã bị lỗi thời, không nên sử dụng vì không chuyển đổi byte sang ký tự đúng cách. Thay vào đó, sử dụng BufferedReader.readLine().

↳ String readUTF(): Đọc một chuỗi được mã hóa theo định dạng UTF-8 từ luồng.

↳ long readLong(): Đọc một số nguyên 64 bit từ luồng.

↳ short readShort(): Đọc một số nguyên 16 bit từ luồng.

↳ int readUnsignedByte(): Đọc một byte không dấu (0-255) từ luồng.

↳ int readUnsignedShort(): Đọc một số nguyên không dấu 16 bit từ luồng.

↳ int skipBytes(int n): Bỏ qua n byte trong luồng.

↳ static String readUTF(DataInput in): Phương thức tĩnh để đọc một chuỗi UTF-8 từ một đối tượng DataInput.

↳ void readFully(byte[] b, int off, int len): Đọc đầy đủ một phần của mảng byte từ luồng, chặn cho đến khi đọc xong.

↳ int readInt(): Đọc một số nguyên 32 bit từ luồng.

Ví dụ 1

Ghi dữ liệu: Chương trình này ghi dữ liệu mẫu vào tệp data.dat, sau đó bạn có thể sử dụng chúng để thử nghiệm với các ví dụ sử dụng DataInputStream bên dưới.

Ví dụ: Example.java

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Example {
    public static void main(String[] args) {
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.dat"))) {
            dos.writeInt(5);
            dos.writeDouble(3.14);
            dos.writeBoolean(true);
            dos.writeUTF("Hello, DataInputStream!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Khi chương trình chạy thành công, tệp data.dat sẽ chứa nội dung như sau:

���@     �Q�¬�Hello, DataInputStream!

Ví dụ 2

Đọc các kiểu dữ liệu nguyên thủy từ tệp data.dat

Ví dụ: Example.java

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Example {
    public static void main(String[] args) {
        try (DataInputStream dis = new DataInputStream(new FileInputStream("data.dat"))) {
            int intValue = dis.readInt();
            double doubleValue = dis.readDouble();
            boolean booleanValue = dis.readBoolean();
            String stringValue = dis.readUTF();

            System.out.println("Giá Trị Integer: " + intValue);
            System.out.println("Giá Trị Double: " + doubleValue);
            System.out.println("Giá Trị Boolean: " + booleanValue);
            System.out.println("Giá Trị String: " + stringValue);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Chạy chương trình này sẽ đọc file data.dat và in ra thông tin:

Giá Trị Integer: 5
Giá Trị Double: 3.14
Giá Trị Boolean: true
Giá Trị String: Hello, DataInputStream!

Ví dụ 3

Đọc dữ liệu từ một chuỗi byte

Ví dụ: Example.java

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;

public class Example {
    public static void main(String[] args) {
        byte[] data = {0, 0, 0, 5, 64, 9, 33, -5, 84, 68, 45, -24, 1};

        try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data))) {
            int intValue = dis.readInt();
            double doubleValue = dis.readDouble();
            boolean booleanValue = dis.readBoolean();

            System.out.println("Giá Trị Integer: " + intValue);
            System.out.println("Giá Trị Double: " + doubleValue);
            System.out.println("Giá Trị Boolean: " + booleanValue);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Kết quả của chương trình là:

Giá Trị Integer: 5
Giá Trị Double: 3.1415926535898855
Giá Trị Boolean: true

Giải thích:

byte[] data: Mảng byte chứa dữ liệu để đọc, trong đó:

↳ 0, 0, 0, 5 tương ứng với số nguyên (int) 5.

↳ 64, 9, 33, -5, 84, 68, 45, -24 là đại diện cho số thực (double) 3.141592653589793.

↳ 1 là giá trị boolean true.

Đọc dữ liệu:

↳ dis.readInt() đọc 4 byte đầu tiên (0, 0, 0, 5) và chuyển đổi thành số nguyên 5.

↳ dis.readDouble() đọc 8 byte tiếp theo (64, 9, 33, -5, 84, 68, 45, -24) và chuyển đổi thành số thực 3.141592653589793.

↳ dis.readBoolean() đọc byte cuối cùng (1) và chuyển đổi thành giá trị boolean true.

Câu Nói Truyền Cảm Hứng

“Bắt đầu ở đâu không quan trọng, quan trọng là bạn sẵn sàng bắt đầu.” – W. Clement Stone

Không Gian Tích Cực

“Chúc bạn luôn giữ vững niềm tin và sức mạnh để vượt qua mọi thử thách trong cuộc sống.”