openplanning

Hướng dẫn và ví dụ Java InputStream

  1. InputStream
  2. read()
  3. read(byte[])
  4. read(byte[], int, int)
  5. readAllBytes()
  6. readNBytes(int len)
  7. readNBytes(byte[] b, int off, int len)
  8. close()
  9. skip(long)
  10. transferTo(OutputStream)
  11. markSupported()
  12. mark(int)
  13. reset()

1. InputStream

InputStream là một lớp nằm trong package java.io, nó là một lớp cơ sở đại diện cho một dòng chảy của các bytes (stream of bytes) có được khi đọc một nguồn dữ liệu nào đó, chẳng hạn file.
public abstract class InputStream implements Closeable
Về cơ bản bạn không thể sử dụng lớp InputStream một cách trực tiếp vì nó là một lớp trừu tượng, tuy nhiên trong trường hợp cụ thể bạn có thể sử dụng một trong các lớp con của nó.
Hãy xem một ví dụ về một file văn bản được mã hoá UTF-8:
utf8-file-without-bom.txt
JP日本-八洲
UTF-8 sử dụng 1, 2, 3 hoặc 4 bytes để lưu trữ một ký tự. Hình ảnh dưới đây cho thấy các bytes trong file nói trên.
FileInputStream là một lớp con của InputStream thường được sử dụng để đọc các file và chúng ta sẽ nhận được một dòng chảy các bytes (stream of bytes).
InputStream Methods
public static InputStream nullInputStream()

public abstract int read() throws IOException  

public int read(byte[] b) throws IOException  
public int read(byte[] b, int off, int len) throws IOException

public byte[] readAllBytes() throws IOException
public byte[] readNBytes(int len) throws IOException  
public int readNBytes(byte[] b, int off, int len) throws IOException  

public long skip(long n) throws IOException  
public int available() throws IOException  

public void close() throws IOException  
public synchronized void mark(int readlimit)  
public synchronized void reset() throws IOException  

public boolean markSupported()  
public long transferTo(OutputStream out) throws IOException

2. read()

public int read() throws IOException
Phương thức read() được sử dụng để đọc một byte, giá trị của byte được trả về là một số nguyên (integer) trong khoảng 0 đến 255, hoặc trả về -1 nếu đã tiến tới cuối stream.
Phương thức này sẽ chặn (block) cho tới khi byte sẵn có để đọc hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.
utf8-file-without-bom.txt
JP日本-八洲
Ví dụ:
InputStream_read_ex1.java
package org.o7planning.inputstream.ex;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStream_read_ex1 {
    
    // Windows path: C:/somepath/utf8-file-without-bom.txt"
    private static final String filePath = "/Volumes/Data/test/utf8-file-without-bom.txt";

    public static void main(String[] args) throws IOException {
        // FileInputStream is a subclass of InputStream.
        InputStream is = new FileInputStream(filePath);

        int code;
        while((code = is.read()) != -1) {
            System.out.println(code + " " + (char)code);
        }
        is.close();
    }
}
Output:
74 J
80 P
230 æ
151 —
165 ¥
230 æ
156 œ
172 ¬
45 -
229 å
133 …
171 «
230 æ
180 ´
178 ²

3. read(byte[])

public int read(byte[] b) throws IOException
Phương thức read(byte[]) đọc các bytes từ InputStream và gán vào các phần tử của mảng và trả về số bytes vừa đọc được. Phương thức này trả về -1 nếu đã tiến tới cuối stream.
Phương thức này sẽ chặn (block) cho tới khi các bytes sẵn có để đọc hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.
Về cơ bản sử dụng phương thức read(byte[]) sẽ có hiệu xuất cao hơn so với phương thức read(), vì nó giảm số lần cần đọc từ stream.
InputStream_read_ex2.java
package org.o7planning.inputstream.ex;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class InputStream_read_ex2 {

    public static void main(String[] args) throws IOException {
        String url = "https://s3.o7planning.com/txt/utf8-file-without-bom.txt";

        InputStream is = new URL(url).openStream();

        // Create a temporary byte array.
        byte[] tempByteArray = new byte[10];
        int byteCount = -1;

        int nth = 0;
        while ((byteCount = is.read(tempByteArray)) != -1) {
            nth++;
            System.out.println("--- Read th: " + nth + " ---");
            System.out.println(" >> Number of bytes read: " + byteCount +"\n");
            
            for(int i= 0; i < byteCount; i++) {
                // bytes are in range [-128,127]
                // Convert byte to unsigned byte. [0, 255].
                int code = tempByteArray[i] & 0xff;
                
                System.out.println(tempByteArray[i] + "    " + code + "    " + (char)code);
            }
        }
        is.close();
    }
}
Output:
--- Read th: 1 ---
 >> Number of bytes read: 10

74    74    J
80    80    P
-26    230    æ
-105    151    —
-91    165    ¥
-26    230    æ
-100    156    œ
-84    172    ¬
45    45    -
-27    229    å
--- Read th: 2 ---
 >> Number of bytes read: 5

-123    133    …
-85    171    «
-26    230    æ
-76    180    ´
-78    178    ²
Chú ý: Kiểu dữ liệu byte bao gồm các số nguyên (integer) nằm trong phạm vi từ -128 đến 127. Bạn có thể chuyển đổi nó thành số nguyên không dấu (unsigned integer) có phạm vi từ 0 đến 255.
  • Convert byte to unsigned byte

4. read(byte[], int, int)

public int read(byte[] b, int offset, int len) throws IOException
Phương thức read(byte[],int,int) đọc các bytes và gán vào các phần tử của mảng từ chỉ số offset tới chỉ số offset+len, và trả về số bytes vừa đọc được. Phương thức này trả về -1 nếu đã tiến tới cuối stream.
Phương thức này sẽ chặn (block) cho tới khi các bytes sẵn có để đọc, hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.

5. readAllBytes()

public byte[] readAllBytes() throws IOException
Ví dụ:
InputStream_readAllBytes_ex1.java
package org.o7planning.inputstream.ex;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class InputStream_readAllBytes_ex1 {

    public static void main(String[] args) throws IOException {
        String url = "https://s3.o7planning.com/txt/utf8-file-without-bom.txt";

        InputStream is = new URL(url).openStream();

        byte[] allBytes = is.readAllBytes();
        String content = new String(allBytes, "UTF-8");
        System.out.println(content);

        is.close();
    }
}
Output:
JP日本-八洲

6. readNBytes(int len)

public byte[] readNBytes(int len) throws IOException
Phương thức readNBytes(int) đọc tối đa "len"bytes từ InputStream, và trả về một mảng byte đọc được. Nếu mảng trả về là rỗng nghĩa là đã tiến tới cuối stream.
Phương thức này sẽ chặn (block) cho tới khi "len"bytes được đọc, hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.
Ví dụ:
InputStream_readNBytes_ex1.java
package org.o7planning.inputstream.ex;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStream_readNBytes_ex1 {
    
    // Windows path: C:/somepath/utf8-file-without-bom.txt"
    private static final String filePath = "/Volumes/Data/test/utf8-file-without-bom.txt";

    public static void main(String[] args) throws IOException {
        // FileInputStream is a subclass of InputStream.
        InputStream is = new FileInputStream(filePath);

        byte[] bytes = null;
        int nth = 0;
        while( true) {
            nth++;
            bytes = is.readNBytes(10);
            
            System.out.println("--- Read th: " + nth + " ---");
            System.out.println(" >> Number of bytes read: " + bytes.length +"\n");
            
            
            if(bytes.length == 0) {
                break;
            }
            for(int i= 0; i< bytes.length; i++) {
                // bytes are in range [-128,127]
                // Convert byte to unsigned byte. [0, 255].
                int code = bytes[i] & 0xff;
                
                System.out.println(bytes[i] + "    " + code + "    " + (char)code);
            }
        }
        is.close();
    }
}
Output:
--- Read th: 1 ---
 >> Number of bytes read: 10

74    74    J
80    80    P
-26    230    æ
-105    151    —
-91    165    ¥
-26    230    æ
-100    156    œ
-84    172    ¬
45    45    -
-27    229    å
--- Read th: 2 ---
 >> Number of bytes read: 5

-123    133    …
-85    171    «
-26    230    æ
-76    180    ´
-78    178    ²
--- Read th: 3 ---
 >> Number of bytes read: 0

7. readNBytes(byte[] b, int off, int len)

public int readNBytes(byte[] b, int offset, int len) throws IOException
Phương thức readNBytes(byte[],int,int) đọc tối đa "len"bytes từ InputStream, và gán các bytes đọc được vào các phần tử của mảng từ chỉ số offset đến offset+len, và trả về số bytes đọc được. Trả về -1 nếu đã tiến tới cuối stream.
read(byte[],int,int) vs readNBytes(byte[],int,int)
public int read(byte[] b, int offset, int len) throws IOException  

public int readNBytes(byte[] b, int offset, int len) throws IOException
Hai phương thức read(byte[],int,int)readNBytes(byte[],int,int) khá giống nhau. Nhưng điều khác biệt có thể xẩy ra trong tình huống sau:
Phương thức read(byte[] b,int offset, int len) không đảm bảo rằng "len" bytes sẽ được đọc từ stream cho dù chưa tiến tới cuối stream.
Phương thức readNBytes(byte[] b,int offset, int len) đảm bảo rằng "len" bytes sẽ được đọc từ stream nếu chưa tiến tới cuối của stream.

8. close()

public void close() throws IOException
Đóng stream này và giải phóng mọi tài nguyên hệ thống được liên kết với nó. Khi stream đã bị đóng, các lệnh gọi tiếp read(), mark(), reset() hoặc skip() sẽ tạo ra một IOException. Đóng stream đã đóng trước đó không có tác dụng.
public interface Closeable extends AutoCloseable
Lớp InputStream thi hành interface Closeable. Nếu bạn viết code theo quy tắc của AutoCloseable thì hệ thống sẽ tự đóng stream cho bạn mà không cần phải gọi trực tiếp phương thức close().
InputStream_close_ex1.java
package org.o7planning.inputstream.ex;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStream_close_ex1 {
    
    // Or Windows path: C:/Somefolder/utf8-file-without-bom.txt
    private static final String file_path = "/Volumes/Data/test/utf8-file-without-bom.txt";

    public static void main(String[] args) throws IOException {
        
        // (InputStream class implements Closeable)
        // (Closeable interface extends AutoCloseable)
        // try block will automatically close stream for you.
        try (InputStream fileInputStream= new FileInputStream(file_path)) {
            int code;
            while((code = fileInputStream.read()) !=  -1)  {
                System.out.println(code +"  " + (char)code);
            }  
        } // end try
    }
}
  • Hướng dẫn và ví dụ Java Closeable

9. skip(long)

public long skip(long n) throws IOException
Phương thức skip(long) bỏ qua "n"bytes.
Phương thức này sẽ chặn (block) cho tới khi các bytes sẵn có hoặc xẩy ra lỗi IO, hoặc đã tiến tới cuối stream.
InputStream_skip_ex1.java
package org.o7planning.inputstream.ex;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStream_skip_ex1 {

    public static void main(String[] args) throws IOException {
        
        String s = "123456789-987654321-ABCDE";
        byte[] bytes = s.getBytes();
        
        // ByteArrayInputStream is a subclass of InputStream.
        InputStream is = new ByteArrayInputStream(bytes);

        int firstByteCode = is.read();
        int secondByteCode = is.read();

        System.out.println("First byte: " + (char) firstByteCode);
        System.out.println("Second byte: " + (char) secondByteCode);

        is.skip(18); // Skips 18 bytes.

        int code;
        while ((code = is.read()) != -1) {
            System.out.println(code +" " + (char) code);
        }
        is.close();
    }
}
Output:
First byte: 1
Second byte: 2
65 A
66 B
67 C
68 D
69 E

10. transferTo(OutputStream)

// Java 10+
public long transferTo(OutputStream out) throws IOException
Phương thức transferTo(OutputStream) được sử dụng để đọc tất cả các bytes từ InputStream hiện tại và ghi chúng vào đối tượng OutputStream đã cho, và trả về số bytes đã chuyển sang OutputStream. Sau khi hoàn thành, đối tượng InputStream hiện tại sẽ ở cuối của stream. Phương thức này sẽ không đóng đối tượng InputStream hiện tại cũng như đối tượng OutputStream.
InputStream_transferTo_ex1.java
package org.o7planning.inputstream.ex;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class InputStream_transferTo_ex1 {

    public static void main(String[] args) throws IOException {
        String s = "123456789-987654321-ABCDE";
        byte[] bytes = s.getBytes();
        
        // ByteArrayInputStream is a subclass of InputStream.
        InputStream reader = new ByteArrayInputStream(bytes);

        // Or Windows path: C:/Somepath/out-file.txt
        File file = new File("/Volumes/Data/test/out-file.txt");
        // Create parent folder.
        file.getParentFile().mkdirs();

        OutputStream writer = new FileOutputStream(file);

        reader.skip(10); // Skips 10 bytes.

        reader.transferTo(writer);

        reader.close();
        writer.close();
    }
}
Output:
out-file.txt
987654321-ABCDE

11. markSupported()

public boolean markSupported()
Phương thức markSupported() được sử dụng để kiểm tra đối tượng InputStream hiện tại có hỗ trợ hoạt động mark(int) hay không. (Xem thêm phương thức mark(int))

12. mark(int)

public void mark(int readAheadLimit) throws IOException
Phương thức mark(int) cho phép bạn đánh dấu vị trí hiện tại trên stream. Bạn có thể đọc tiếp các bytes tiếp theo, và gọi phương thức reset() để quay trở lại vị trí đã đánh dấu trước đó. Trong đó readAheadLimit là số bytes tối đa có thể đọc sau khi đánh dấu mà không làm mất vị trí đã đánh dấu.
Chú ý: Không phải tất cả các InputStream đều hỗ trợ hoạt động mark(int). Để chắc chắn bạn cần gọi phương thức markSupported() để kiểm tra xem đối tượng InputStream hiện tại có hỗ trợ hoạt động đó hay không.
InputStream_mark_ex1.java
package org.o7planning.inputstream.ex;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStream_mark_ex1 {

    public static void main(String[] args) throws IOException {
        
        String s = "123456789-987654321-ABCDE";
        byte[] bytes = s.getBytes(); // byte[]{'1','2', .... 'E'}
        
        // ByteArrayInputStream is a subclass of InputStream.
        InputStream is = new ByteArrayInputStream(bytes);


        is.skip(10); // Skips 10 bytes.

        System.out.println("ByteArrayInputStream markSupported? " + is.markSupported()); // true
        
        is.mark(9);
        
        int code1 = is.read();
        int code2 = is.read();
        
        System.out.println(code1 + "  " + (char) code1); // '9'
        System.out.println(code2 + "  " + (char) code2); // '8'
        is.skip(5);
        
        System.out.println("Reset");
        is.reset(); // Return to the marked position.
        
        int code;
        while((code = is.read())!= -1) {
            System.out.println(code + "  " + (char)code);
        }
        is.close();
    }
}
Output:
ByteArrayInputStream markSupported? true
57  9
56  8
Reset
57  9
56  8
55  7
54  6
53  5
52  4
51  3
50  2
49  1
45  -
65  A
66  B
67  C
68  D
69  E

13. reset()

public void reset() throws IOException
Nếu đối tượng InputStream này hỗ trợ việc đánh dấu vị trí hiện tại thông qua phương thức mark(int), thì phương thức reset() được sử dụng để quay trở lại vị trí đã được đánh dấu.

Các hướng dẫn Java IO

Show More