Klasa ByteArrayInputStream pakietu java.io może służyć do odczytywania tablicy danych wejściowych (w bajtach).

Aby utworzyć strumień wejściowy tablicy bajtów, musimy najpierw zaimportować pakiet java.io.ByteArrayInputStream . Po zaimportowaniu pakietu mamy dwóch konstruktorów do utworzenia strumienia wejściowego:


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

Wewnątrz klasy znajdują się 4 pola:


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

A oto nasi konstruktorzy:


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

Metody ByteArrayInputStream

metoda Działanie
intread() Odczytuje następny bajt danych z tego strumienia wejściowego.
int read(bajt b[], int off, int len) Odczytuje określoną liczbę bajtów ze strumienia wejściowego i zapisuje je w tablicy buforów b .
off jest początkowym przesunięciem w tablicy docelowej b .
len to maksymalna liczba odczytanych bajtów.
długie pominięcie (długie n) Pomija n bajtów danych wejściowych z tego strumienia wejściowego. Zwraca liczbę pominiętych bajtów (może być mniejsza, jeśli osiągnięto koniec strumienia wejściowego).
int dostępne() Zwraca liczbę pozostałych bajtów, które można odczytać (lub pominąć) z tego strumienia wejściowego.
anuluj reset() Resetuje bufor do zaznaczonej pozycji. Zaznaczona pozycja to 0, chyba że zaznaczono inną pozycję lub określono inne przesunięcie w konstruktorze.
znak logicznyObsługiwane() Sprawdza, czy ten InputStream obsługuje tagowanie/resetowanie. Zwraca true dla ByteArrayInputStream .
nieważne zamknięcie() Nic nie robić.
znak nieważności (int readAheadLimit) Ustawia aktualną pozycję w poluocena. Jeśli metoda resetowania zostanie wywołana , kolejny odczyt rozpocznie się od tej pozycji. Wartość parametru metody readAheadLimit nie wpływa na jej działanie i po prostu nie jest używana.

Przyjrzyjmy się bliżej tym metodom i zobaczmy, jak działają w praktyce.

Czytać()

Jeśli chcesz odczytać bajty z ByteArrayInputStream w taki sam sposób, jak z normalnego InputStream , możesz użyć metody 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();
   }
}
    

dostępny()

Jeśli chcesz sprawdzić, czy coś jest w twoim buforze, możesz wywołać metodę 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();
   }
}
    

W rezultacie zobaczymy, że liczba bajtów dostępnych do odczytu zmienia się po każdym odczycie z bufora.

Wyjście programu:

bajty dostępne do odczytu 4
bajty wolne do odczytu 3
bajty wolne do odczytu 2

pomiń (długie n)

Za pomocą metody skip() możesz pominąć określoną liczbę bajtów i ich nie czytać.


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

Wyjście programu:

3, 4,

Resetowanie()

Metoda resetuje pozycję buforowanego strumienia do ostatniej zaznaczonej pozycji. Zajmuje pozycję etykiety 0, chyba że wyraźnie określono inną etykietę.


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

W rezultacie zobaczymy, jak po wywołaniu metody reset() dostaniemy się do punktu startowego naszego strumienia.

Wyjście programu:

odczyt: 65
odczyt: 66
odczyt: 67
odczyt: 68
wywołanie metody reset()
odczyt: 65
odczyt: 66

mark(int readAheadLimit)

Metoda mark() klasy ByteArrayInputStream ustawia wewnętrzny znacznik na bieżącej pozycji bajtu, czyli zaraz po odczytaniu poprzedniego bajtu. Ta metoda przyjmuje parametr wskazujący, ile bajtów można odczytać po tym znaku, zanim stanie się nieprawidłowy. Domyślnie, jeśli etykieta nie została ustawiona jawnie, ByteArrayInputStream etykietuje pozycję 0 lub pozycję z przesunięciem przekazanym do swojego konstruktora. Należy zauważyć, że flaga readAheadLimit jest nieprawidłowa dla tej klasy.


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

Oto przykład ustawiania etykiety na obiekcie ByteArrayInputStream przy użyciu metody mark() i metody reset() . Dodamy wywołanie metody mark() do poprzedniego przykładu :


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

W rezultacie widzimy, że pozycja aktualnego wątku już się zmieniła.

Wyjście programu:

odczyt: 65
odczyt: 66
odczyt: 67
odczyt: 68
odczyt: 69
wywołanie metody reset()
odczyt: 68
odczyt: 69

markObsługiwane()

Metoda markSupported() pozwala sprawdzić dostęp do ustawienia znaku. Aby zrozumieć, na czym opiera się wynik, przejdźmy do metody:


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

Nasza metoda zawsze zwraca true . Sprawdźmy to na przykładzie:


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

W efekcie po wykonaniu metody mark() oraz reset() nasz stream jest zawsze gotowy i może stawiać znaczniki:

Wyjście programu:

isMarkSupported: true
odczyt: 65
odczyt: 66
odczyt: 67
isMarkSupported: true
isMarkSupported: true

zamknąć()

Aby zrozumieć, jak działa metoda close , przyjrzymy się również jej zawartości:


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

Dokumentacja metody close mówi, że zamknięcie ByteArrayInputStream nie ma żadnego efektu. Metody klasy ByteArrayInputStream można wywołać po zamknięciu strumienia bez zgłaszania wyjątku IOException .

Jaki wniosek możemy wyciągnąć?

Potrzebujemy ByteArrayInputStream , gdy musimy odczytać dane z tablicy bajtów. Zwykle sensowne jest używanie tej klasy nie samodzielnie, ale w połączeniu z innym kodem, który wie, jak pracować z InputStream .