La classe ByteArrayInputStream nel pacchetto java.io può essere utilizzata per leggere un array di input (di byte).

Per creare un flusso di input di array di byte, dobbiamo prima importare il pacchetto java.io.ByteArrayInputStream . Dopo aver importato il pacchetto, abbiamo due costruttori disponibili per la creazione di un flusso di input:

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

Ci sono 4 campi all'interno della classe:

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

Ed ecco i nostri costruttori:

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

Metodi della classe ByteArrayInputStream

Metodo Azione
int leggi() Legge il successivo byte di dati da questo flusso di input.
int read(byte b[], int off, int len) Legge diversi byte dal flusso di input e li archivia nella matrice di buffer b .
off è un offset nell'array di destinazione b .
len è il numero massimo di byte da leggere.
salto lungo (lungo n) Salta n byte di input da questo flusso di input. Restituisce il numero di byte saltati (potrebbe essere minore di n se raggiungiamo la fine del flusso di input).
int disponibile() Restituisce il numero di byte rimanenti che possono essere letti (o ignorati) da questo flusso di input.
reset vuoto() Reimposta il buffer nella posizione contrassegnata. La posizione contrassegnata è 0 a meno che non sia contrassegnata un'altra posizione o non sia specificato un diverso offset nel costruttore.
contrassegno booleanoSupportato() Controlla se questo InputStream supporta la marcatura/reimpostazione. Restituisce true per ByteArrayInputStream .
void close() Non fa niente.
contrassegno void(int readAheadLimit) Imposta ilsegnocampo uguale alla posizione corrente. Se viene chiamato il metodo di ripristino , la lettura successiva inizierà da quella posizione. Il parametro readAheadLimit non viene utilizzato e non influisce sul comportamento del metodo.

Diamo un'occhiata più da vicino a questi metodi e vediamo come funzionano nella pratica.

Leggere()

Quando vuoi leggere byte da un ByteArrayInputStream proprio come faresti da un normale InputStream , puoi usare il metodo 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();
   }
}

disponibile()

Se vuoi controllare se c'è qualcosa nel tuo buffer, puoi chiamare il metodo 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();
   }
}

Vedremo che il numero di byte disponibili per la lettura cambia dopo ogni lettura dal buffer.

Produzione:

Byte disponibili per la lettura: 4
Byte disponibili per la lettura: 3
Byte disponibili per la lettura: 2

salta(n lunga)

Puoi usare il metodo skip() per saltare un certo numero di byte e non leggerli.

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

Produzione:

3, 4,

Ripristina()

Questo metodo reimposta la posizione del flusso memorizzato nel buffer sull'ultima posizione contrassegnata. È la posizione 0 a meno che non sia impostato un segno diverso.

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

Vedremo che chiamare il metodo reset() ci porta al punto di partenza del nostro stream.

Produzione:

Lettura: 65
Lettura: 66
Lettura: 67
Lettura: 68
Chiamata del metodo reset()
Lettura: 65
Lettura: 66

mark(int readAheadLimit)

Il metodo mark() della classe ByteArrayInputStream imposta il contrassegno interno nella posizione del byte corrente, ovvero immediatamente dopo il byte letto in precedenza. Questo metodo accetta un parametro che indica quanti byte possono essere letti dopo il contrassegno prima che il flusso diventi non valido. Per impostazione predefinita, se il contrassegno non è impostato in modo esplicito, un ByteArrayInputStream contrassegna la posizione 0 o la posizione dell'offset passato al relativo costruttore. È importante notare che il segno readAheadLimit è irrilevante per questa classe.

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

Ecco un esempio di come impostare un segno in un ByteArrayInputStream utilizzando i suoi metodi mark() e reset() . Aggiungeremo una chiamata al metodo mark() all'esempio precedente:

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

Possiamo vedere che la posizione del flusso corrente è cambiata.

Produzione:

Lettura: 65
Lettura: 66
Lettura: 67
Lettura: 68
Lettura: 69
Chiamata del metodo reset()
Lettura: 68
Lettura: 69

markSupportato()

Il metodo markSupported() consente di verificare se è possibile impostare un contrassegno. Per capire da dove viene il valore restituito, andiamo al codice del metodo:

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

Il metodo restituisce sempre true . Proviamo questo in pratica.

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

Dopo aver eseguito i metodi mark() e reset() , il nostro stream è sempre pronto e supporta i mark:

Produzione:

isMarkSupported: true
Lettura: 65
Lettura: 66
Lettura: 67
isMarkSupported: true
isMarkSupported: true

vicino()

E per capire il metodo di chiusura , diamo anche un'occhiata al suo interno:

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

La documentazione per il metodo close ci dice che la chiusura di un ByteArrayInputStream non ha alcun effetto. I metodi della classe ByteArrayInputStream possono essere chiamati dopo che il flusso è stato chiuso senza generare un'eccezione IOException .

Cosa possiamo concludere?

Abbiamo bisogno di un ByteArrayInputStream quando vogliamo leggere i dati da un array di byte. Di solito ha senso usare questa classe in combinazione con altro codice che sa come lavorare con InputStreams piuttosto che da solo.