Java >> Java tutorial >  >> Tag >> byte

Java InputStream til Byte Array og ByteBuffer

1. Oversigt

I denne hurtige selvstudie skal vi tage et kig på, hvordan man konverterer en InputStream til en byte[] og ByteBuffer – først ved at bruge almindelig Java, derefter ved at bruge Guava og Commons IO.

Denne artikel er en del af "Java - Back to Basic"-serien her på Baeldung.

Yderligere læsning:

Introduktion til Springs StreamUtils

Oplev Springs StreamUtils-klasse.Læs mere →

Introduktion til Java-serialisering

Vi lærer at serialisere og deserialisere objekter i Java. Læs mere →

Java-strengkonverteringer

Hurtige og praktiske eksempler fokuseret på at konvertere String-objekter til forskellige datatyper i Java.Læs mere →

2. Konverter til Byte Array

Lad os se på at få et byte-array fra simple inputstrømme. Det vigtige aspekt ved et byte-array er, at det muliggør en indekseret (hurtig) adgang til hver 8-bit (en byte) værdi, der er gemt i hukommelsen . Derfor kan du manipulere disse bytes for at kontrollere hver bit. Vi skal se på, hvordan man konverterer en simpel inputstrøm til en byte[] – først ved at bruge almindelig Java, derefter ved at bruge Guava og Apache Commons IO.

2.1. Konverter ved hjælp af almindelig Java

Lad os starte med en Java-løsning, der fokuserer på at håndtere en strøm med fast størrelse:

@Test
public void givenUsingPlainJavaOnFixedSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() 
  throws IOException {
    InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
    byte[] targetArray = new byte[is.available()];

    is.read(targetArray);
}

I tilfælde af en bufferstrøm – hvor vi har at gøre med en bufferstrøm og ikke kender den nøjagtige størrelse af de underliggende data, er vi nødt til at gøre implementeringen mere fleksibel:

@Test
public void givenUsingPlainJavaOnUnknownSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() 
  throws IOException {
    InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5, 6 }); // not really known
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();

    int nRead;
    byte[] data = new byte[4];

    while ((nRead = is.read(data, 0, data.length)) != -1) {
        buffer.write(data, 0, nRead);
    }

    buffer.flush();
    byte[] targetArray = buffer.toByteArray();
}

Fra og med Java 9 kan vi opnå det samme med en dedikeret readNbytes metode:

@Test
public void givenUsingPlainJava9OnUnknownSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect() 
  throws IOException {
    InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5, 6 });
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();

    int nRead;
    byte[] data = new byte[4];

    while ((nRead = is.readNBytes(data, 0, data.length)) != 0) {
        System.out.println("here " + nRead);
        buffer.write(data, 0, nRead);
    }

    buffer.flush();
    byte[] targetArray = buffer.toByteArray();
}

Forskellen mellem disse to metoder er meget subtil.

Den første, læs​(byte[] b, int off, int len) , læser op til len bytes af data fra inputstrømmen , hvorimod den anden, readNBytes​(byte[] b, int off, int len) , læser præcis det ønskede antal bytes .

Derudover læs returnerer -1 hvis der ikke er flere tilgængelige data i inputstrømmen. readNbytes returnerer dog altid det faktiske antal bytes indlæst i bufferen.

Vi kan også læse alle bytes på én gang:

@Test
public void
  givenUsingPlainJava9_whenConvertingAnInputStreamToAByteArray_thenCorrect()
  throws IOException {
    InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 });

    byte[] data = is.readAllBytes();
}

2.2. Konverter ved hjælp af Guava

Lad os nu se på den simple Guava-baserede løsning – ved hjælp af den praktiske ByteStreams-hjælpeklasse:

@Test
public void givenUsingGuava_whenConvertingAnInputStreamToAByteArray_thenCorrect() 
  throws IOException {
    InputStream initialStream = ByteSource.wrap(new byte[] { 0, 1, 2 }).openStream();
    
    byte[] targetArray = ByteStreams.toByteArray(initialStream);
}

2.3. Konverter ved hjælp af Commons IO

Og endelig – en ligetil løsning ved hjælp af Apache Commons IO:

@Test
public void givenUsingCommonsIO_whenConvertingAnInputStreamToAByteArray_thenCorrect() 
  throws IOException {
    ByteArrayInputStream initialStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
    
    byte[] targetArray = IOUtils.toByteArray(initialStream);
}

Metoden IOUtils.toByteArray() buffere input internt, så der er ingen grund til at bruge en BufferedInputStream forekomst når buffering er nødvendig.

3. Konverter til ByteBuffer

Lad os nu se på at få en ByteBuffer fra en InputStream. Dette er nyttigt, når vi har brug for hurtige og direkte I/O-operationer på lavt niveau i hukommelsen .

Ved at bruge samme tilgang som ovenstående sektioner vil vi tage et kig på, hvordan man konverterer en InputStream til en ByteBuffer – først ved at bruge almindelig Java, derefter ved at bruge Guava og Commons IO.

3.1. Konverter ved hjælp af almindelig Java

I tilfælde af en byte-stream - vi kender den nøjagtige størrelse af de underliggende data. Lad os bruge ByteArrayInputStream#available metode til at læse bytestrømmen ind i en ByteBuffer :

@Test
public void givenUsingCoreClasses_whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch() 
  throws IOException {
    byte[] input = new byte[] { 0, 1, 2 };
    InputStream initialStream = new ByteArrayInputStream(input);
    ByteBuffer byteBuffer = ByteBuffer.allocate(3);
    while (initialStream.available() > 0) {
        byteBuffer.put((byte) initialStream.read());
    }

    assertEquals(byteBuffer.position(), input.length);
}

3.2. Konverter ved hjælp af Guava

Lad os nu se på en simpel Guava-baseret løsning – ved hjælp af de praktiske ByteStreams hjælpeklasse:

@Test
public void givenUsingGuava__whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch() 
  throws IOException {
    InputStream initialStream = ByteSource
      .wrap(new byte[] { 0, 1, 2 })
      .openStream();
    byte[] targetArray = ByteStreams.toByteArray(initialStream);
    ByteBuffer bufferByte = ByteBuffer.wrap(targetArray);
    while (bufferByte.hasRemaining()) {
        bufferByte.get();
    }

    assertEquals(bufferByte.position(), targetArray.length);
}

Her bruger vi en while-løkke med metoden hasRemaining for at vise en anden måde at læse alle bytes ind i ByteBuffer. Ellers ville påstanden mislykkes, fordi ByteBuffer indekspositionen vil være nul.

3.3. Konverter ved hjælp af Commons IO

Og endelig – ved at bruge Apache Commons IO og IOUtils klasse:

@Test
public void givenUsingCommonsIo_whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch() 
  throws IOException {
    byte[] input = new byte[] { 0, 1, 2 };
    InputStream initialStream = new ByteArrayInputStream(input);
    ByteBuffer byteBuffer = ByteBuffer.allocate(3);
    ReadableByteChannel channel = newChannel(initialStream);
    IOUtils.readFully(channel, byteBuffer);

    assertEquals(byteBuffer.position(), input.length);
}

4. Konklusion

Denne artikel illustrerede forskellige måder at konvertere en rå inputstrøm til en byte-array og en ByteBuffer ved at bruge almindelig Java, Guava og Apache Commons IO.

Implementeringen af ​​alle disse eksempler kan findes i vores GitHub-projekt.


Java tag