Hướng dẫn sử dụng luồng vào ra nhị phân trong Java

Ở bài viết trước tôi đẫ giới thiệu với các bạn Luồng vào ra (I/O) trong Java. Ở bài này chúng ta sẽ cùng tìm hiểu các lớp hỗ trợ xử lý luồng nhị phân trong Java.

1. Đọc ký tự từ console

1.1. Ví dụ nhập từng ký tự từ bàn phím và hiên thị kết quả lên màn hình

package com.maixuanviet.console;
 
import java.io.IOException;
import java.io.InputStream;
 
public class ReadByteConsole {
 
    public static void main(String[] args) throws IOException {
        InputStream is = System.in;
        while (true) {
            System.out.print("Nhập 1 ký tự: ");
            int ch = is.read();
            if (ch == 'q') {
                System.out.println("Finished!");
                break;
            }
            is.skip(2); // Loại bỏ 2 ký tự \r và \n
            System.out.println("Ký tự nhận được: " + (char) ch);
        }
    }
}

Kết quả thực thi chương trình trên:

Nhập 1 ký tự: g
Ký tự nhận được: g
Nhập 1 ký tự: p
Ký tự nhận được: p
Nhập 1 ký tự: q
Finished!

1.2. Ví dụ nhập một chuỗi ký tự từ bàn phím và hiên thị kết quả lên màn hình

package com.maixuanviet.console;
 
import java.io.IOException;
 
public class ReadByteConsole2 {
 
    public static void main(String[] args) throws IOException {
        while (true) {
            System.out.print("Nhập chuỗi ký tự: ");
            byte[] bytes = new byte[100]; // Tạo vùng đệm để nhập chuỗi
            int length = System.in.read(bytes);
            String str = new String(bytes, 0, length - 2);
            if (str.equalsIgnoreCase("EXIT")) {
                System.out.println("Finished!");
                break;
            }
            System.out.println("Chuỗi nhận được: " + str);
        }
    }
}

Kết quả thực thi chương trình trên:

Nhập chuỗi ký tự: maixuanviet.com
Chuỗi nhận được: maixuanviet.com
Nhập chuỗi ký tự: exit
Finished!

2. Sử dụng FileInputStream và FileOutputStream

Lớp FileInputStream trong java đọc được các byte từ một input file. Nó được sử dụng để đọc dữ liệu theo định dạng byte (các byte stream) như dữ liệu hình ảnh, âm thanh, video vv. Bạn cũng có thể đọc các dữ liệu có định dạng ký tự. Tuy nhiên, để đọc các dòng ký tự (các character stream), bạn nên sử dụng lớp FileReader.

Java FileOutputStream là một output stream được sử dụng để ghi dữ liệu vào một file theo định dạng byte (byte stream). Sử dụng lớp FileOutputStream trong java, nếu bạn phải ghi các giá trị nguyên thủy vào một file. Bạn có thể ghi dữ liệu theo định dạng byte hoặc định dạng ký tự thông qua lớp FileOutputStream. Tuy nhiên, đối với các dữ liệu được ghi theo ký tự, sử dụng FileWriter thích hợp hơn FileOutStream.

2.1. Ví dụ đọc nội dung của file sử dụng FileInputStream

package com.maixuanviet.bytestream;
 
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
 
public class InputStreamExample {
 
    public static void main(String[] args) throws IOException {
 
        // Tạo một đối tượng InputStream: Luồng đọc một file.
        InputStream is = new FileInputStream("data/test.txt");
 
        int i = -1;
 
        // Đọc lần lượt các byte (8bit) trong luồng và lưu vào biến i
        // Khi đọc ra giá trị -1 nghĩa là kết thúc luồng.
        while ((i = is.read()) != -1) {
            System.out.println((char) i);
        }
        is.close();
    }
}

Kết quả thực thi chương trình trên:

H
e
l
l
o
  
I
n
p
u
t
S
t
r
e
a
m

2.2. Ví dụ đọc nhiều byte sử dụng FileInputStream

package com.maixuanviet.bytestream;
 
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
 
public class InputStreamExample2 {
 
    public static void main(String[] args) throws IOException {
 
        // Tạo một luồng đầu vào bằng cách đọc một file
        InputStream in = new FileInputStream("data/test.txt");
 
        // Mảng để mỗi lần đọc các byte từ luồng thì tạm thời để lên đó
        // Ta dùng mảng 10 byte
 
        byte[] bytes = new byte[10];
        int i = -1;
 
        // Đọc các byte trong luồng và gán lên các phần tử của mảng.
        // Giá trị i là số đọc được của 1 lần. (i sẽ <= 10).
        // Khi không còn phần tử trong luồng i sẽ = -1
        while ((i = in.read(bytes)) != -1) {
            // Tạo String từ các byte đọc được
            String s = new String(bytes, 0, i);
            System.out.println(s);
        }
        in.close();
    }
}
&#91;/code&#93;
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>Kết quả thực thi chương trình trên:</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->

Hello Inpu
tStream

2.3. Ví dụ ghi nội dung ra file sử dụng FileOutputStream

package com.maixuanviet.bytestream;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
 
public class OutputStreamExample {
 
    public static void main(String[] args) throws IOException {
        // Tạo một luồng ký tự đầu ra với mục đích ghi thông tin vào file
        OutputStream os = new FileOutputStream("data/output.txt");
 
        // Tạo một mảng byte ,ta sẽ ghi các byte này vào file nói trên .
        byte[] by = new byte[] { 'g', 'p', 'c', 'o', 'd', 'e', 'r', '.', 'c', 'o', 'm' };
 
        // Ghi lần lượt các ký tự vào luồng
        for (int i = 0; i < by.length; i++) {
            byte b = by&#91;i&#93;;
            // Ghi ký tự vào luồng
            os.write(b);
        }
        // Đóng luồng đầu ra lại việc ghi xuống file hoàn tất.
        os.close();
    }
}
&#91;/code&#93;
<!-- /wp:shortcode -->

<!-- wp:heading {"level":3} -->
<h3>2.4. Ví dụ ghi nhiều byte sử dụng&nbsp;FileOutputStream</h3>
<!-- /wp:heading -->

<!-- wp:shortcode -->

package com.maixuanviet.bytestream;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
 
public class OutputStreamExample2 {
 
    public static void main(String[] args) throws IOException {
        // Tạo một luồng nhị phân đầu ra với mục đích ghi thông tin vào file
        OutputStream os = new FileOutputStream("data/output2.txt");
 
        // Tạo một mảng byte ,ta sẽ ghi các byte này vào file nói trên .
        byte[] b1 = new byte[] { 'g', 'p', 'c', 'o', 'd', 'e', 'r' };
        byte[] b2 = new byte[] { '.', 'c', 'o', 'm' };
        byte[] b3 = new byte[] { 13, 10 }; // Xuống dòng mới
        byte[] b4 = new byte[] { 'I', '/', 'O' };
 
        // Ghi cả các byte trong mảng byte[] by vào luồng
        os.write(b1);
 
        // Đẩy các byte hiện có trên luồng xuống file .
        os.flush();
 
        // Tiếp tục ghi các byte trong mảng thứ 2 vào luồng
        os.write(b2);
        os.write(b3);
        os.write(b4);
 
        // Đóng luồng vào công việc ghi thành công .
        os.close();
    }
}

3. Sử dụng ByteArrayInputStream & ByteArrayOutputStream

ByteArrayInputStream bao gồm hai từ: ByteArray và InputStream. Tên của nó cho thấy, nó có thể được sử dụng để đọc mảng byte như là input stream.

  • Lớp ByteArrayInputStream trong java chứa một bộ đệm bên trong được sử dụng để đọc mảng byte dưới dạng luồng.
  • Bộ đệm của ByteArrayInputStream tự động tăng theo kích thước dữ liệu.

Lớp ByteArrayOutputStream trong java được sử dụng để ghi dữ liệu chung vào nhiều file. Trong luồng này, dữ liệu được ghi vào mảng byte có thể được ghi vào nhiều stream sau đó.

  • ByteArrayOutputStream giữ một bản sao của dữ liệu và chuyển tiếp nó đến nhiều stream.
  • Bộ đệm của ByteArrayOutputStream tự động tăng theo kích thước dữ liệu.

3.1. Ví dụ sử dụng ByteArrayInputStream

package com.maixuanviet.bytestream;
 
import java.io.ByteArrayInputStream;
import java.io.IOException;
 
public class ByteArrayInputStreamExample {
 
    public static void main(String args[]) throws IOException {
 
        byte[] buf = new byte[] { 'g', 'p', 'c', 'o', 'd', 'e', 'r', '.', 'c', 'o', 'm' };
        // Create the new byte array input stream
        ByteArrayInputStream byt = new ByteArrayInputStream(buf);
        int k = 0;
        while ((k = byt.read()) != -1) {
            // Conversion of a byte into character
            char ch = (char) k;
            System.out.println("ASCII value of Character is:" + k + " - Special character is: " + ch);
        }
    }
}

Kết quả thực thi chương trình trên:

ASCII value of Character is:103 - Special character is: g
ASCII value of Character is:112 - Special character is: p
ASCII value of Character is:99 - Special character is: c
ASCII value of Character is:111 - Special character is: o
ASCII value of Character is:100 - Special character is: d
ASCII value of Character is:101 - Special character is: e
ASCII value of Character is:114 - Special character is: r
ASCII value of Character is:46 - Special character is: .
ASCII value of Character is:99 - Special character is: c
ASCII value of Character is:111 - Special character is: o
ASCII value of Character is:109 - Special character is: m

3.2. Ví dụ sử dụng ByteArrayOutputStream

package com.maixuanviet.bytestream;
 
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
 
public class ByteArrayOutputStreamExample {
 
    public static void main(String args[]) throws IOException {
 
        FileOutputStream fout1 = new FileOutputStream("data/f1.txt");
        FileOutputStream fout2 = new FileOutputStream("data/f2.txt");
 
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        bout.write(65);
        bout.writeTo(fout1);
        bout.writeTo(fout2);
 
        bout.flush();
        bout.close();// has no effect
        System.out.println("Success...");
    }
}

Thực thi chương trình trên: có 2 file f1 và f2 được tạo ra trong thư mục data của project.

Hình bên dưới minh họa hoạt động của ví dụ này:

4. Sử dụng ObjectInputStream và ObjectOutputStream

ObjectInputStream, ObjectOutputStream cho phép bạn đọc hoặc ghi một Object vào luồng. Các Object này phải là kiểu Serializable.

Student.java

package com.maixuanviet.bytestream;
 
import java.io.Serializable;
 
public class Student implements Serializable {
 
    private static final long serialVersionUID = -266706354210367639L;
 
    private int id;
    private String name;
    private int age;
 
    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + "]";
    }
}

4.1. Ví dụ sử dụng ObjectOutputStream để ghi đối tượng vào file

package com.maixuanviet.bytestream;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
 
public class ObjectOutputStreamExample {
    public static void main(String args[]) throws Exception {
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("data/student.txt"));
            Student student = new Student(1, "maixuanviet.com", 28);
            oos.writeObject(student);
            oos.flush();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            oos.close();
        }
        System.out.println("success...");
    }
}

4.2. Ví dụ sử dụng ObjectInputStreamExample để đọc đối tượng từ file

package com.maixuanviet.bytestream;
 
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
 
public class ObjectInputStreamExample {
    public static void main(String args[]) throws Exception {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("data/student.txt"));
            Student student = (Student) ois.readObject();
            System.out.println(student);
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            ois.close();
        }
    }
}

Thực thi chương trình ObjectOutputStreamExample, một file student.txt được tạo ra trong thư mục data của project như sau:

Thực thi chương trình ObjectInputStreamExample, ta được nội dung như sau:

Student [id=1, name=maixuanviet.com, age=28]

5. Sử dụng DataInputStream và DataOutputStream

Lớp DataInputStream trong java cho phép một ứng dụng đọc dữ liệu nguyên thủy từ luồng đầu vào một cách độc lập với máy. Ứng dụng Java thường sử dụng DataOutputStream để ghi dữ liệu mà sau này có thể được đọc bởi một DataInputStream.

Lớp DataOutputStream trong java cho phép một ứng dụng ghi các kiểu dữ liệu Java nguyên thủy đến output stream một cách độc lập với máy. Ứng dụng Java thường sử dụng DataOutputStream để ghi dữ liệu mà sau này có thể được đọc bởi một DataInputStream.

5.1. Ví dụ ghi file sử dụng DataOutputStream

package com.maixuanviet.bytestream;
 
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
 
public class DataOutputStreamExamaple {
 
    public static void main(String[] args) throws IOException {
 
        int id = 1;
        String name = "maixuanviet.com";
 
        OutputStream file = new FileOutputStream("data/test3.txt");
        DataOutputStream data = new DataOutputStream(file);
         
        data.writeInt(id);
        data.writeUTF(name);
         
        data.flush();
        data.close();
        System.out.println("Succcess...");
    }
}

Thực thi chương trình trên, một file test3.txt được tạo ra trong thư mục data của dự án.

5.2. Ví dụ đọc file sử dụng DataInputStream

package com.maixuanviet.bytestream;
 
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
 
public class DataInputStreamExample {
 
    public static void main(String[] args) throws IOException {
 
        InputStream input = new FileInputStream("data/test3.txt");
        DataInputStream inst = new DataInputStream(input);
 
        int id = inst.readInt();
        String name = inst.readUTF();
 
        System.out.println("Id: " + id + ", Name: " + name);
 
        inst.close();
    }
}

Kết quả thực thi chương trình trên:

Id: 1, Name: maixuanviet.com

6. Sử dụng FilterInputStream và FilterOutputStream

Lớp FilterOutputStream trong java extends lớp OutputStream. Nó cung cấp các lớp con khác nhau như BufferedOutputStream và DataOutputStream để cung cấp các chức năng bổ sung. Vì vậy, nó ít được sử dụng riêng lẻ.

Lớp FilterInputStream trong java extends lớp InputStream. Nó cung cấp các lớp con khác nhau như BufferedInputStream và DataInputStream để cung cấp chức năng bổ sung. Vì vậy, nó ít được sử dụng riêng lẻ.

6.1. Ví dụ ghi file sử dụng FilterOutputStream

package com.maixuanviet.bytestream;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
 
public class FilterOutputStreamExample {
    public static void main(String[] args) throws IOException {
        FileOutputStream file = null;
        FilterOutputStream filter = null;
        try {
            file = new FileOutputStream(new File("data/test.txt"));
            filter = new FilterOutputStream(file);
            String s = "maixuanviet.com";
            byte b[] = s.getBytes();
            filter.write(b);
            filter.flush();
            System.out.println("Success...");
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            filter.close();
            file.close();
        }
    }
}

Thực thi chương trình trên, một file test.txt được tạo ra trong thư mục data của project.

6.2. Ví dụ đọc file sử dụng FilterInputStream

package com.maixuanviet.bytestream;
 
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
 
public class FilterInputStreamExample {
    public static void main(String[] args) throws IOException {
        FileInputStream file = null;
        FilterInputStream filter = null;
        try {
            file = new FileInputStream(new File("data/test.txt"));
            filter = new BufferedInputStream(file);
 
            int k = 0;
            while ((k = filter.read()) != -1) {
                System.out.print((char) k);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        file.close();
        filter.close();
    }
}

Kết quả thực thi chương trình trên:

maixuanviet.com

7. Sử dụng SequenceInputStream

Thông thường bạn đã quen thuộc với việc đọc một file nào đó và thu được một luồng đầu vào .Nhưng trong thực tế đôi khi bạn cần đọc từ nhiều file và lấy các dữ liệu đó ghép với nhau để ghi thành 1 file khác chẳng hạn .Vậy là ý tưởng ghép nhiều luồng đầu vào với nhau để thành một luồng lớn hơn nối đuôi nhau . Chúng ta đang nói đến class java.io.SequenceInputStream. Khái niệm này không có tương ứng cho luồng đầu ra.

package com.maixuanviet.bytestream;
 
import java.io.FileInputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
 
public class SequenceInputStreamExample {
    public static void main(String args[]) throws Exception {
        FileInputStream input1 = null;
        FileInputStream input2 = null;
        SequenceInputStream inst = null;
        try {
            input1 = new FileInputStream("data/test1.txt");
            input2 = new FileInputStream("data/test2.txt");
            inst = new SequenceInputStream(input1, input2);
            int j;
            while ((j = inst.read()) != -1) {
                System.out.print((char) j);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            inst.close();
            input1.close();
            input2.close();
        }
    }
}

8. Sử dụng PipedInputStream và PipedOutputStream

Đặt ra một tình huống bạn có 2 luồng một luồng đầu vào và một luồng đầu ra. Chẳng hạn luồng đầu vào dữ liệu A đọc một file , lấy thông tin từ luồng này ghi vào luồng dữ liệu B đầu ra là một file khác. Hai luồng A và B trong tình huống này là tách riêng nhau. Vì vậy trong ứng dụng bạn phải có 3 thao tác:

  • Tạo luồng dữ liệu đọc A
  • Tạo luồng ghi dữ liệu B
  • Đọc từ A ghi vào B …

Hai thao tác đầu phải có, nhưng bạn muốn bỏ đi thao tác thứ 3. Nghĩa là có một cái gì đó liên hệ ngầm với nhau giữa 2 luồng (vào-ra) ,để sao cho những byte xuất hiện trên luồng đầu đọc A lập tức được ghi tự động vào B. Đó được gọi là liên hệ đường ngầm giữa 2 luồng vào và ra.

package com.maixuanviet.bytestream;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
 
public class PipeStreamExample {
    private InputStream pipedInputStream;
 
    public static void main(String[] args) throws IOException, InterruptedException {
        new PipeStreamExample().test();
    }
 
    private void test() throws IOException, InterruptedException {
        // Tạo một 'pipedOutputStream',
        PipedOutputStream pipedOutputStream = new PipedOutputStream();
 
        // Dữ liệu ghi vào 'pipedOutputStream'
        // sẽ tự động xuất hiện tại 'pipedInputStream'.
        pipedInputStream = new PipedInputStream(pipedOutputStream);
 
        new ThreadRead().start();
 
        char[] chs = new char[] { 'a', 'a', 'b', 'c', 'e' };
 
        // Ghi dữ liệu vào 'pipedOutputStream'.
        for (char ch : chs) {
            pipedOutputStream.write(ch);
            Thread.sleep(1000);
        }
        pipedOutputStream.close();
    }
 
    // Một Thread đọc dữ liệu xuất hiện trên 'pipedInputStream'.
    class ThreadRead extends Thread {
 
        @Override
        public void run() {
            try {
                int data = 0;
                while ((data = pipedInputStream.read()) != -1) {
                    System.out.println((char) data);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                closeQuietly(pipedInputStream);
            }
        }
    }
 
    private void closeQuietly(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
            }
        }
    }
}

Kết quả thực thi chương trình trên:

a
a
b
c
e

1 Trackback / Pingback

  1. Hướng dẫn sử dụng luồng vào ra ký tự trong Java – Blog của VietMX

Comments are closed.