Lớp ByteArrayInputStream trong gói java.io có thể được sử dụng để đọc một mảng đầu vào (của byte).

Để tạo luồng đầu vào mảng byte, trước tiên chúng ta phải nhập gói java.io.ByteArrayInputStream . Sau khi chúng tôi nhập gói, chúng tôi có sẵn hai hàm tạo để tạo luồng đầu vào:

ByteArrayInputStream input = new ByteArrayInputStream(arr);
ByteArrayInputStream input = new ByteArrayInputStream(arr, 2, 2);

Có 4 trường bên trong lớp:

// Byte array provided by the creator of the stream
protected byte buf[];

// Index of the next character to read from the input stream's buffer
protected int pos;

// Current marked position in the stream
protected int mark = 0;

// Index is one greater than the last valid character in the input stream's buffer
protected int count;

Và đây là các nhà xây dựng của chúng tôi:

public ByteArrayInputStream(byte buf[]) {
    this.buf = buf;
    this.pos = 0;
    this.count = buf.length;
}

public ByteArrayInputStream(byte buf[], int offset, int length) {
    this.buf = buf;
    this.pos = offset;
    this.count = Math.min(offset + length, buf.length);
    this.mark = offset;
}

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

Phương pháp Hoạt động
int đã đọc() Đọc byte dữ liệu tiếp theo từ luồng đầu vào này.
int đã đọc(byte b[], int tắt, int len) Đọc một số byte từ luồng đầu vào và lưu trữ chúng trong mảng bộ đệm b .
off là phần bù vào mảng mục tiêu b .
len là số byte tối đa để đọc.
bỏ qua dài (dài n) Bỏ qua n byte đầu vào từ luồng đầu vào này. Trả về số byte đã bỏ qua (có thể nhỏ hơn n nếu chúng ta đến cuối luồng đầu vào).
int có sẵn() Trả về số byte còn lại có thể được đọc (hoặc bỏ qua) từ luồng đầu vào này.
đặt lại khoảng trống() Đặt lại bộ đệm về vị trí đã đánh dấu. Vị trí được đánh dấu là 0 trừ khi một vị trí khác được đánh dấu hoặc một phần bù khác được chỉ định trong hàm tạo.
dấu booleanHỗ trợ() Kiểm tra xem InputStream này có hỗ trợ đánh dấu/đặt lại hay không. Trả về true cho ByteArrayInputStream .
đóng khoảng trống () Không làm bất cứ điều gì.
dấu vô hiệu (int readAheadLimit) Đặtđánh dấutrường bằng với vị trí hiện tại. Nếu phương thức đặt lại được gọi, thì quá trình đọc tiếp theo sẽ bắt đầu từ vị trí đó. Tham số readAheadLimit không được sử dụng và không ảnh hưởng đến hành vi của phương thức.

Chúng ta hãy xem xét kỹ hơn các phương pháp này và xem chúng hoạt động như thế nào trong thực tế.

đọc()

Khi bạn muốn đọc byte từ ByteArrayInputStream giống như cách bạn làm từ InputStream thông thường , bạn có thể sử dụng phương thức read() .

public static void main(String[] args) {
   byte[] array = {1, 2, 3, 4};

   try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
       for (int i = 0; i < array.length; i++) {
           int data = input.read();
           System.out.print(data + ", ");
       }
   } catch (IOException e) {
       e.printStackTrace();
   }
}

có sẵn()

Nếu bạn muốn kiểm tra xem có thứ gì trong bộ đệm của mình hay không, bạn có thể gọi phương thức available() .

public static void main(String[] args) {
   byte[] array = {1, 2, 3, 4};

   try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
       System.out.println("Bytes available for reading: " + input.available());

       input.read();
       System.out.println("Bytes available for reading " + input.available());

       input.read();
       System.out.println("Bytes available for reading " + input.available());
   } catch (IOException e) {
       e.printStackTrace();
   }
}

Chúng ta sẽ thấy rằng số byte có sẵn để đọc thay đổi sau mỗi lần đọc từ bộ đệm.

Đầu ra:

Số byte khả dụng để đọc: 4
Byte khả dụng để đọc: 3
Byte khả dụng để đọc: 2

bỏ qua (dài n)

Bạn có thể sử dụng phương thức skip() để bỏ qua một số byte nhất định và không đọc chúng.

public static void main(String[] args) {
   byte[] array = {1, 2, 3, 4};

   try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
       input.skip(2);

       while (input.available() != 0) {
           int data = input.read();
           System.out.print(data + ", ");
       }
   } catch (IOException e) {
       e.printStackTrace();
   }
}

Đầu ra:

3, 4,

cài lại()

Phương pháp này đặt lại vị trí của luồng được đệm về vị trí được đánh dấu cuối cùng. Đó là vị trí 0 trừ khi một dấu khác được đặt.

public static void main(String[] args) {
   byte[] buf = {65, 66, 67, 68, 69};
   try (ByteArrayInputStream input = new ByteArrayInputStream(buf)) {
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());

       System.out.println("Calling reset() method");
       input.reset();
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
   } catch (IOException e) {
       e.printStackTrace();
   }
}

Chúng ta sẽ thấy rằng việc gọi phương thức reset() sẽ đưa chúng ta đến điểm bắt đầu của luồng.

Đầu ra:

Đọc: 65
Đọc: 66
Đọc: 67
Đọc: 68
Gọi phương thức reset()
Đọc: 65
Đọc: 66

đánh dấu (int readAheadLimit)

Phương thức mark() của lớp ByteArrayInputStream đặt dấu bên trong ở vị trí byte hiện tại, tức là ngay sau byte đã đọc trước đó. Phương thức này nhận một tham số cho biết có thể đọc bao nhiêu byte sau dấu trước khi luồng của nó trở nên không hợp lệ. Theo mặc định, nếu dấu không được đặt rõ ràng, ByteArrayInputStream sẽ đánh dấu vị trí 0 hoặc vị trí của phần bù được truyền cho hàm tạo của nó. Điều quan trọng cần lưu ý là dấu readAheadLimit không liên quan đến lớp này.

/* Note: For this class, {@code readAheadLimit}
*  has no meaning.
*
* @since   1.1
*/
public void mark(int readAheadLimit) {
   mark = pos;
}

Dưới đây là ví dụ về cách đặt dấu trong ByteArrayInputStream bằng các phương thức mark()reset() của nó . Chúng ta sẽ thêm lệnh gọi phương thức mark() vào ví dụ trước:

public static void main(String[] args) {
   byte[] buf = {65, 66, 67, 68, 69};
   try (ByteArrayInputStream input = new ByteArrayInputStream(buf)) {
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());
       input.mark(5);

       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());

       System.out.println("Calling reset() method");
       input.reset();

       System.out.println("Read: " + input.read());
       System.out.println("Read: " + input.read());

   } catch (IOException e) {
       e.printStackTrace();
   }
}

Chúng ta có thể thấy rằng vị trí của luồng hiện tại đã thay đổi.

Đầu ra:

Đọc: 65
Đọc: 66
Đọc: 67
Đọc: 68
Đọc: 69
Gọi phương thức reset()
Đọc: 68
Đọc: 69

đánh dấuHỗ trợ()

Phương thức markSupported() cho phép bạn kiểm tra xem có thể đặt một dấu hay không. Để hiểu giá trị trả về đến từ đâu, hãy xem mã của phương thức:

/**
* Tests if this {@code InputStream} supports mark/reset. The
* {@code markSupported} method of {@code ByteArrayInputStream}
* always returns {@code true}.
*
* @since   1.1
*/
public boolean markSupported() {
   return true;
}

Phương thức luôn trả về true . Hãy kiểm tra điều này trong thực tế.

public static void main(String[] args) {
   byte[] buf = {65, 66, 67, 68, 69};
   try (ByteArrayInputStream bais = new ByteArrayInputStream(buf)) {
       boolean isMarkSupported = bais.markSupported();

       System.out.println("isMarkSupported: " + isMarkSupported);
       System.out.println("Read: " + bais.read());
       System.out.println("Read: " + bais.read());

       bais.mark(1);
       System.out.println("Read: " + bais.read());
       isMarkSupported = bais.markSupported();
       System.out.println("isMarkSupported: " + isMarkSupported);

       bais.reset();
       isMarkSupported = bais.markSupported();
       System.out.println("isMarkSupported: " + isMarkSupported);
   } catch (IOException e) {
       e.printStackTrace();
   }
}

Sau khi thực hiện các phương thức mark()reset() , luồng của chúng ta luôn sẵn sàng và hỗ trợ các dấu:

Đầu ra:

isMarkSupported: true
Đọc: 65
Đọc: 66
Đọc: 67
isMarkSupported: true
isMarkSupported: true

đóng()

Và để hiểu phương thức đóng , chúng ta cũng hãy xem qua bên trong nó:

/**
* Closing a {@code ByteArrayInputStream} has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an {@code IOException}.
*/
public void close() throws IOException {
}

Tài liệu về phương thức đóng cho chúng ta biết rằng việc đóng ByteArrayInputStream không có hiệu lực. Các phương thức lớp ByteArrayInputStream có thể được gọi sau khi đóng luồng mà không ném IOException .

Chúng ta có thể kết luận điều gì?

Chúng ta cần ByteArrayInputStream khi muốn đọc dữ liệu từ một mảng byte. Việc sử dụng lớp này kết hợp với mã khác biết cách làm việc với InputStreams thường là hợp lý hơn là sử dụng riêng nó.