Класът ByteArrayInputStream в пакета java.io може да се използва за четене на входен масив (от byteове).

За да създадем входен поток от byteов масив, първо трябва да импортираме пакета java.io.ByteArrayInputStream . След като импортираме пакета, имаме два налични конструктора за създаване на входен поток:

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

Вътре в класа има 4 полета:

// 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;

А ето и нашите конструктори:

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;
}

Методи на класа ByteArrayInputStream

Метод Действие
int read() Чете следващия byte данни от този входен поток.
int read(byte b[], int off, int len) Чете няколко byteа от входния поток и ги съхранява в буферен масив b .
off е отместване в целевия масив b .
len е максималният брой byteове за четене.
дълго прескачане (дълго n) Пропуска n byteа вход от този входен поток. Връща броя на пропуснатите byteове (може да е по-малко от n, ако стигнем до края на входния поток).
int наличен() Връща броя на оставащите byteове, които могат да бъдат прочетени (or пропуснати) от този входен поток.
void reset() Нулира буфера до маркираната позиция. Маркираната позиция е 0, освен ако не е маркирана друга позиция or в конструктора е указано различно отместване.
булево markSupported() Проверява дали този InputStream поддържа маркиране/нулиране. Връща true за ByteArrayInputStream .
void close() Не прави нищо.
void mark (int readAheadLimit) Задавамаркаполе, равно на текущата позиция. Ако се извика методът за нулиране , последващото четене ще започне от тази позиция. Параметърът readAheadLimit не се използва и не засяга поведението на метода.

Нека разгледаме по-подробно тези методи и да видим How работят на практика.

Прочети()

Когато искате да прочетете byteове от ByteArrayInputStream точно Howто бихте направor от обикновен InputStream , можете да използвате метода 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();
   }
}

на разположение()

Ако искате да проверите дали има нещо във вашия буфер, можете да извикате метода 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();
   }
}

Ще видим, че броят на наличните byteове за четене се променя след всяко четене от буфера.

Изход:

Байта, налични за четене: 4
byteа, налични за четене: 3
byteа, налични за четене: 2

пропускане (дълго n)

Можете да използвате метода skip() , за да пропуснете определен брой byteове и да не ги четете.

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();
   }
}

Изход:

3, 4,

нулиране()

Този метод нулира позицията на буферирания поток до последната маркирана позиция. Това е позиция 0, освен ако не е зададена друга маркировка.

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();
   }
}

Ще видим, че извикването на метода reset() ни отвежда до началната точка на нашия поток.

Изход:

Четене: 65
Четене: 66
Четене: 67
Четене: 68
Извикване на метод reset()
Четене: 65
Четене: 66

марка (int readAheadLimit)

Методът mark() на класа ByteArrayInputStream задава вътрешната маркировка на текущата позиция на byteа, тоест непосредствено след прочетения преди това byte. Този метод приема параметър, който показва колко byteа могат да бъдат прочетени след маркировката, преди потокът да стане невалиден. По подразбиране, ако знакът не е зададен изрично, ByteArrayInputStream маркира позиция 0 or позицията на отместването, предадено на неговия конструктор. Важно е да се отбележи, че знакът readAheadLimit е неуместен за този клас.

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

Ето пример за задаване на знак в ByteArrayInputStream с помощта на неговите методи mark() и reset() . Ще добавим извикване към метода mark() към предишния пример:

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();
   }
}

Виждаме, че позицията на текущия поток се е променила.

Изход:

Четене: 65
Четене: 66
Четене: 67
Четене: 68
Четене: 69
Извикване на метод reset()
Четене: 68
Четене: 69

markSupported()

Методът markSupported() ви позволява да проверите дали може да бъде зададена маркировка. За да разберем откъде идва върнатата стойност, нека отидем на codeа на метода:

/**
* 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;
}

Методът винаги връща true . Нека тестваме това на практика.

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();
   }
}

След изпълнение на методите mark() и reset() , нашият поток винаги е готов и поддържа марки:

Изход:

isMarkSupported: true
Прочетено: 65
Прочетено: 66
Прочетено: 67
isMarkSupported: true
isMarkSupported: true

близо()

И за да разберем близкия метод, нека надникнем и в него:

/**
* 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 {
}

Документацията за метода за затваряне ни казва, че затварянето на ByteArrayInputStream няма ефект. Методите на клас ByteArrayInputStream могат да бъдат извикани след затваряне на потока, без да се хвърля IOException .

Какво можем да заключим?

Имаме нужда от ByteArrayInputStream , когато искаме да прочетем данни от byteов масив. Обикновено има смисъл да се използва този клас в комбинация с друг code, който знае How да работи с InputStreams , а не сам.