Xử lý luồng dữ liệu (Input/Output Streams) trong Java

7 minute read

V. Xử lý luồng dữ liệu (Input/Output Streams) trong Java:

A. Đọc và ghi dữ liệu với FileInputStream và FileOutputStream:

Trong Java, FileInputStreamFileOutputStream là hai lớp được sử dụng để đọc và ghi dữ liệu từ và vào các tập tin trong hệ thống tệp của bạn.

  1. FileInputStream:

    • FileInputStream được sử dụng để đọc dữ liệu từ một tập tin trong hệ thống tệp của bạn.
    • Ví dụ dưới đây mô tả cách sử dụng FileInputStream để đọc dữ liệu từ một tập tin:
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      
      try {
          FileInputStream fis = new FileInputStream("input.txt");
          int data;
          while ((data = fis.read()) != -1) {
              // Xử lý dữ liệu ở đây
              System.out.print((char) data); // In dữ liệu ra màn hình
          }
          fis.close();
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  2. FileOutputStream:

    • FileOutputStream được sử dụng để ghi dữ liệu vào một tập tin trong hệ thống tệp của bạn.
    • Ví dụ sau minh họa cách sử dụng FileOutputStream để ghi dữ liệu vào một tập tin:
      1
      2
      3
      4
      5
      6
      7
      8
      
      try {
          FileOutputStream fos = new FileOutputStream("output.txt");
          String data = "Hello, world!";
          fos.write(data.getBytes());
          fos.close();
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  3. Đóng luồng dữ liệu:

    • Rất quan trọng khi sử dụng luồng dữ liệu là phải đảm bảo rằng chúng đã được đóng sau khi sử dụng xong để giải phóng tài nguyên.
    • Điều này có thể được thực hiện trong khối finally hoặc sử dụng cú pháp try-with-resources của Java.

Sử dụng cú pháp try-with-resources của Java

là một cách tiện lợi và an toàn để đảm bảo rằng các luồng dữ liệu được đóng sau khi không còn cần thiết. Bằng cách này, bạn không cần phải viết mã để đóng luồng một cách tường minh trong khối finally.

Dưới đây là cách sử dụng cú pháp try-with-resources cho việc đóng luồng dữ liệu trong Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Sử dụng try-with-resources để tự động đóng luồng dữ liệu
try (DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"))) {
    int intValue = dis.readInt();
    double doubleValue = dis.readDouble();
    boolean booleanValue = dis.readBoolean();
    System.out.println("int value: " + intValue);
    System.out.println("double value: " + doubleValue);
    System.out.println("boolean value: " + booleanValue);
} catch (IOException e) {
    e.printStackTrace();
}
1
2
3
4
5
6
7
8
// Sử dụng try-with-resources để tự động đóng luồng dữ liệu
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"))) {
    dos.writeInt(42);
    dos.writeDouble(3.14);
    dos.writeBoolean(true);
} catch (IOException e) {
    e.printStackTrace();
}

Khi sử dụng cú pháp này, không cần phải gọi phương thức close() trực tiếp trên luồng. Java sẽ tự động đóng luồng sau khi khối try kết thúc, bất kể là có xảy ra ngoại lệ hay không. Điều này giúp mã của bạn trở nên ngắn gọn và dễ đọc hơn.

Việc sử dụng FileInputStreamFileOutputStream cho phép bạn đọc và ghi dữ liệu vào các tập tin trong Java một cách đơn giản và hiệu quả. Đảm bảo rằng bạn đóng luồng sau khi sử dụng để tránh rò rỉ tài nguyên.

B. Đọc và ghi dữ liệu với DataInputStream và DataOutputStream:

Trong Java, DataInputStreamDataOutputStream là hai lớp con của InputStreamOutputStream tương ứng. Chúng cung cấp các phương thức để đọc và ghi các loại dữ liệu nguyên thủy như int, double, boolean, vv.

  1. DataInputStream:

    • DataInputStream được sử dụng để đọc các loại dữ liệu nguyên thủy từ luồng đầu vào.
    • Ví dụ dưới đây mô tả cách sử dụng DataInputStream để đọc dữ liệu từ một tập tin:
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      try {
          DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"));
          int intValue = dis.readInt();
          double doubleValue = dis.readDouble();
          boolean booleanValue = dis.readBoolean();
          System.out.println("int value: " + intValue);
          System.out.println("double value: " + doubleValue);
          System.out.println("boolean value: " + booleanValue);
          dis.close();
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  2. DataOutputStream:

    • DataOutputStream được sử dụng để ghi các loại dữ liệu nguyên thủy vào luồng đầu ra.
    • Ví dụ sau minh họa cách sử dụng DataOutputStream để ghi dữ liệu vào một tập tin:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      try {
          DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"));
          dos.writeInt(42);
          dos.writeDouble(3.14);
          dos.writeBoolean(true);
          dos.close();
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  3. Đóng luồng dữ liệu:

    • Như trong trường hợp của các luồng dữ liệu khác, đảm bảo rằng bạn đóng DataInputStreamDataOutputStream sau khi sử dụng để giải phóng tài nguyên.

Việc sử dụng DataInputStreamDataOutputStream giúp bạn dễ dàng đọc và ghi các loại dữ liệu nguyên thủy như int, double, boolean, và nhiều loại dữ liệu khác vào và ra khỏi tập tin hoặc luồng dữ liệu.

C. Đọc và ghi dữ liệu với ObjectInputStream và ObjectOutputStream:

Trong Java, ObjectInputStreamObjectOutputStream là hai lớp con của InputStreamOutputStream tương ứng. Chúng được sử dụng để đọc và ghi các đối tượng Java vào và ra khỏi luồng dữ liệu.

  1. ObjectInputStream:

    • ObjectInputStream được sử dụng để đọc các đối tượng Java từ một luồng đầu vào.
    • Ví dụ dưới đây mô tả cách sử dụng ObjectInputStream để đọc các đối tượng từ một tập tin:
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      
      try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("objects.dat"))) {
          Object obj;
          while ((obj = ois.readObject()) != null) {
              // Xử lý đối tượng được đọc
              System.out.println(obj);
          }
      } catch (EOFException e) {
          // Đọc hết tập tin
      } catch (IOException | ClassNotFoundException e) {
          e.printStackTrace();
      }
      
  2. ObjectOutputStream:

    • ObjectOutputStream được sử dụng để ghi các đối tượng Java vào một luồng đầu ra.
    • Ví dụ sau minh họa cách sử dụng ObjectOutputStream để ghi các đối tượng vào một tập tin:
      1
      2
      3
      4
      5
      6
      7
      
      try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("objects.dat"))) {
          oos.writeObject(new Person("John", 30));
          oos.writeObject(new Person("Alice", 25));
          oos.writeObject(new Person("Bob", 35));
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  3. Đóng luồng dữ liệu:

    • Như trong trường hợp của các luồng dữ liệu khác, đảm bảo rằng bạn đóng ObjectInputStreamObjectOutputStream sau khi sử dụng để giải phóng tài nguyên.

Việc sử dụng ObjectInputStreamObjectOutputStream giúp bạn dễ dàng đọc và ghi các đối tượng Java vào và ra khỏi tập tin hoặc luồng dữ liệu. Bạn chỉ cần chắc chắn rằng các đối tượng bạn muốn ghi là tuân thủ giao diện Serializable.

D. Xử lý luồng văn bản với InputStreamReader và OutputStreamWriter:

Trong Java, InputStreamReaderOutputStreamWriter là hai lớp được sử dụng để đọc và ghi dữ liệu văn bản từ và vào các luồng dữ liệu byte. Chúng chuyển đổi các luồng dữ liệu byte thành luồng dữ liệu văn bản và ngược lại, bằng cách sử dụng các bộ mã hóa được chỉ định hoặc mặc định.

  1. InputStreamReader:

    • InputStreamReader được sử dụng để đọc dữ liệu văn bản từ một luồng dữ liệu byte đầu vào.
    • Ví dụ dưới đây mô tả cách sử dụng InputStreamReader để đọc dữ liệu văn bản từ một luồng dữ liệu byte:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      try (InputStreamReader isr = new InputStreamReader(new FileInputStream("input.txt"), "UTF-8")) {
          int data;
          while ((data = isr.read()) != -1) {
              // Xử lý dữ liệu văn bản
              System.out.print((char) data); // In dữ liệu ra màn hình
          }
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  2. OutputStreamWriter:

    • OutputStreamWriter được sử dụng để ghi dữ liệu văn bản vào một luồng dữ liệu byte đầu ra.
    • Ví dụ sau minh họa cách sử dụng OutputStreamWriter để ghi dữ liệu văn bản vào một luồng dữ liệu byte:
      1
      2
      3
      4
      5
      6
      
      try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("output.txt"), "UTF-8")) {
          String data = "Hello, world!";
          osw.write(data);
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  3. Đóng luồng dữ liệu:

    • Như trong trường hợp của các luồng dữ liệu khác, đảm bảo rằng bạn đóng InputStreamReaderOutputStreamWriter sau khi sử dụng để giải phóng tài nguyên.

Việc sử dụng InputStreamReaderOutputStreamWriter cho phép bạn đọc và ghi dữ liệu văn bản một cách dễ dàng và hiệu quả từ và vào các luồng dữ liệu byte trong Java.

E. Xử lý luồng dữ liệu nâng cao với BufferedInputStream và BufferedOutputStream:

Trong Java, BufferedInputStreamBufferedOutputStream là hai lớp con của InputStreamOutputStream tương ứng. Chúng được sử dụng để cải thiện hiệu suất đọc và ghi dữ liệu bằng cách sử dụng bộ nhớ đệm, giảm số lần truy cập vào ổ đĩa.

  1. BufferedInputStream:

    • BufferedInputStream cung cấp một bộ đệm để đọc dữ liệu từ một luồng đầu vào.
    • Ví dụ dưới đây mô tả cách sử dụng BufferedInputStream để đọc dữ liệu từ một tập tin:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("input.txt"))) {
          int data;
          while ((data = bis.read()) != -1) {
              // Xử lý dữ liệu
              System.out.print((char) data); // In dữ liệu ra màn hình
          }
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  2. BufferedOutputStream:

    • BufferedOutputStream cung cấp một bộ đệm để ghi dữ liệu vào một luồng đầu ra.
    • Ví dụ sau minh họa cách sử dụng BufferedOutputStream để ghi dữ liệu vào một tập tin:
      1
      2
      3
      4
      5
      6
      
      try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("output.txt"))) {
          String data = "Hello, world!";
          bos.write(data.getBytes());
      } catch (IOException e) {
          e.printStackTrace();
      }
      
  3. Đóng luồng dữ liệu:

    • Như trong trường hợp của các luồng dữ liệu khác, đảm bảo rằng bạn đóng BufferedInputStreamBufferedOutputStream sau khi sử dụng để giải phóng tài nguyên.

Việc sử dụng BufferedInputStreamBufferedOutputStream giúp tăng hiệu suất đọc và ghi dữ liệu bằng cách sử dụng bộ đệm, giảm số lần truy cập vào ổ đĩa, và làm cho việc xử lý dữ liệu trở nên nhanh chóng và hiệu quả hơn.