Konvertieren Sie InputStream in ein Byte-Array in Java


Antworten:


1135

Sie können Apache Commons IO verwenden , um diese und ähnliche Aufgaben zu erledigen.

Der IOUtilsTyp verfügt über eine statische Methode zum Lesen InputStreamund Zurückgeben von a byte[].

InputStream is;
byte[] bytes = IOUtils.toByteArray(is);

Intern erstellt dies ein ByteArrayOutputStreamund kopiert die Bytes in die Ausgabe und ruft dann auf toByteArray(). Es verarbeitet große Dateien, indem die Bytes in Blöcken von 4 KB kopiert werden.


188
Wenn Sie 4 Codezeilen schreiben möchten, halten Sie den Import einer Abhängigkeit von Drittanbietern für sinnvoll?
oxbow_lakes

217
Wenn es eine Bibliothek gibt, die die Anforderungen erfüllt, sich mit der Verarbeitung großer Dateien befasst und gut getestet ist, ist die Frage sicherlich, warum ich sie selbst schreiben sollte. Das Glas ist nur 107 KB groß und wenn Sie eine Methode benötigen, werden Sie wahrscheinlich auch andere verwenden
Rich Seller

242
@oxbow_lakes: die erstaunliche Menge von unter Berücksichtigung falschen Implementierungen dieser Funktion , die ich in meinem Entwickler Leben gesehen habe, habe ich das Gefühl , dass ja es ist sehr die externe Abhängigkeit bekommen es richtig viel wert.
Joachim Sauer

17
Schauen Sie sich doch einmal Apache Commons FastArrayListoder deren weiche und schwache Referenzkarten an und kommen Sie zurück, um mir zu sagen, wie "gut getestet" diese Bibliothek ist. Es ist ein Müllhaufen
oxbow_lakes

87
Überprüfen Sie zusätzlich zu Apache commons-io die ByteStreams- Klasse von Google Guava . InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
Michaelok

446

Sie müssen jedes Byte von Ihrem lesen InputStreamund in ein schreiben ByteArrayOutputStream.

Sie können das zugrunde liegende Byte-Array dann abrufen, indem Sie Folgendes aufrufen toByteArray():

InputStream is = ...
ByteArrayOutputStream buffer = new ByteArrayOutputStream();

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

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

return buffer.toByteArray();

16
Was ist mit der Größe des neu erstellten Bytes []? Warum ist es 16384? Wie kann ich die genau richtige Größe bestimmen? Vielen Dank.
Ondrej Bozek

6
16384 ist eine ziemlich willkürliche Wahl, obwohl ich eher Zweierpotenzen bevorzuge, um die Wahrscheinlichkeit zu erhöhen, dass sich das Array an Wortgrenzen ausrichtet. Die Antwort von pihentagy zeigt, wie Sie die Verwendung eines Zwischenpuffers vermeiden, sondern ein Array mit der richtigen Größe zuweisen können. Sofern es sich nicht um große Dateien handelt, bevorzuge ich persönlich den obigen Code, der eleganter ist und für InputStreams verwendet werden kann, bei denen die Anzahl der zu lesenden Bytes nicht im Voraus bekannt ist.
Adamski

@Adamski Ist das Erstellen eines Bytes nicht viel größer als erwartet, verschwenden Sie den Speicher?
Paul Brewczynski

@bluesm: Ja das stimmt. In meinem Beispiel ist das Byte-Array jedoch nur 16 KB groß und nach heutigen Maßstäben so klein. Natürlich wird dieser Speicher auch danach wieder freigegeben.
Adamski

5
@Adamski Viele Infrastrukturhardware, Webserver und Komponenten auf Betriebssystemebene verwenden 4K-Puffer, um Daten zu verschieben. Dies ist der Grund für die genaue Anzahl. Der Hauptpunkt ist jedoch, dass Sie durch das Überschreiten von 4K einen so geringen Leistungsschub erzielen dass es allgemein als verschwenderisch für das Gedächtnis angesehen wird. Ich gehe davon aus, dass dies immer noch wahr ist, weil es zehn Jahre altes Wissen ist, das ich hatte!


132

Verwenden Sie Vanille-Java DataInputStreamund seine readFullyMethode (existiert seit mindestens Java 1.4):

...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...

Es gibt einige andere Varianten dieser Methode, aber ich verwende diese ständig für diesen Anwendungsfall.


45
+1 für die Verwendung der Standardbibliotheken anstelle einer Abhängigkeit von Drittanbietern. Leider funktioniert es bei mir nicht, da ich die Länge des Streams nicht im Voraus kenne.
Andrew Spencer

2
Was ist imgFile? Es kann kein InputStream sein, der die Eingabe dieser Methode sein sollte
Janus Troelsen

4
@janus es ist eine "Datei". Diese Methode funktioniert nur, wenn Sie die Länge der Datei oder die Anzahl der zu lesenden Bytes kennen.
Dermoritz

5
Interessant, aber Sie müssen die genaue Länge des (Teils des) Streams kennen, um ihn lesen zu können. Darüber hinaus wird die Klasse DataInputStreamprimär zum Lesen von Primärtypen (Longs, Shorts, Chars ...) aus einem Stream verwendet, sodass wir diese Verwendung als Missbrauch der Klasse ansehen können.
Olivier Faucheux

17
Wenn Sie bereits die Länge der Daten kennen, die aus dem Stream gelesen werden sollen, ist dies nicht besser als InputStream.read.
Logan Pickup


46

Wie immer hat auch Spring Framework (Spring-Core seit 3.2.2) etwas für Sie:StreamUtils.copyToByteArray()


Wie die meisten anderen wollte ich vermeiden, eine Bibliothek eines Drittanbieters für etwas so Einfaches zu verwenden, aber Java 9 ist im Moment keine Option ... zum Glück habe ich Spring bereits verwendet.
Scottysseus

42
public static byte[] getBytesFromInputStream(InputStream is) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    byte[] buffer = new byte[0xFFFF];
    for (int len = is.read(buffer); len != -1; len = is.read(buffer)) { 
        os.write(buffer, 0, len);
    }
    return os.toByteArray();
}

2
Es ist ein Beispiel und als solches ist Kürze an der Tagesordnung. In einigen Fällen wäre es auch die richtige Wahl, hier null zurückzugeben (obwohl Sie in einer Produktionsumgebung auch eine ordnungsgemäße Ausnahmebehandlung und Dokumentation hätten).

11
Ich verstehe die Kürze in einem Beispiel, aber warum sollte die Beispielmethode nicht einfach IOException auslösen, anstatt sie zu verschlucken und einen bedeutungslosen Wert zurückzugeben?
Pendor

4
Ich habe mir die Freiheit genommen, von 'return null' zu 'throw IOException' zu
wechseln

3
Das Ausprobieren mit Ressourcen ist hier nicht erforderlich, da ByteArrayOutputStream # close () nichts tut. (ByteArrayOutputStream # flush () wird nicht benötigt und tut auch nichts.)
Luke Hutchison

25

Sichere Lösung (mitclosekorrekterFähigkeit derStreams):

  • Java 9+ Version:

    final byte[] bytes;
    try (inputStream) {
        bytes = inputStream.readAllBytes();
    }
  • Java 8 Version:

    public static byte[] readAllBytes(InputStream inputStream) throws IOException {
        final int bufLen = 4 * 0x400; // 4KB
        byte[] buf = new byte[bufLen];
        int readLen;
        IOException exception = null;
    
        try {
            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                while ((readLen = inputStream.read(buf, 0, bufLen)) != -1)
                    outputStream.write(buf, 0, readLen);
    
                return outputStream.toByteArray();
            }
        } catch (IOException e) {
            exception = e;
            throw e;
        } finally {
            if (exception == null) inputStream.close();
            else try {
                inputStream.close();
            } catch (IOException e) {
                exception.addSuppressed(e);
            }
        }
    }
  • Kotlin- Version (wenn Java 9+ nicht verfügbar ist):

    @Throws(IOException::class)
    fun InputStream.readAllBytes(): ByteArray {
        val bufLen = 4 * 0x400 // 4KB
        val buf = ByteArray(bufLen)
        var readLen: Int = 0
    
        ByteArrayOutputStream().use { o ->
            this.use { i ->
                while (i.read(buf, 0, bufLen).also { readLen = it } != -1)
                    o.write(buf, 0, readLen)
            }
    
            return o.toByteArray()
        }
    }

    Um verschachtelt zu vermeiden, usesiehe hier .


Bedeutet das nicht, dass Sie irgendwann doppelt so viel Speicher haben würden, weil Sie sowohl den Puffer als auch das Byte-Array haben? Gibt es keine Möglichkeit, die Bytes direkt an das Ausgabebyte-Array zu senden?
Android-Entwickler

@Android-Entwickler; Es tut mir Leid. Ich weiß die Antwort nicht! Aber ich denke nicht. Ich denke, dieser Weg (mit Puffer) ist ein optimierter Weg.
Mir-Ismaili

Ich habe es überprüft und es tut es, aber es scheint, dass es die einzige Lösung ist, die Sie wählen können, wenn Sie die Größe nicht kennen. Wenn Sie die Größe bereits kennen, können Sie das Byte-Array mit der angegebenen Größe direkt erstellen und füllen. Sie verwenden also eine Funktion, die einen Parameter der Bytegröße abruft. Wenn dieser gültig ist, können Sie damit das Bytearray direkt erstellen und füllen, ohne ein anderes großes Objekt zu erstellen.
Android-Entwickler

@Android-Entwickler; Vielen Dank für Ihre Informationen. Ich kannte sie nicht.
Mir-Ismaili

19

Benötigen Sie das Bild wirklich als byte[]? Was genau erwarten Sie in derbyte[] - dem vollständigen Inhalt einer Bilddatei, die in einem beliebigen Format der Bilddatei codiert ist, oder von RGB-Pixelwerten?

Andere Antworten hier zeigen Ihnen, wie Sie eine Datei in eine lesen byte[]. Ihr byte[]Testament enthält den genauen Inhalt der Datei, und Sie müssen diesen dekodieren, um etwas mit den Bilddaten zu tun.

Die Standard-API von Java zum Lesen (und Schreiben) von Bildern ist die ImageIO-API, die Sie im Paket finden javax.imageio. Sie können ein Bild aus einer Datei mit nur einer Codezeile einlesen:

BufferedImage image = ImageIO.read(new File("image.jpg"));

Dies gibt Ihnen eine BufferedImage, nicht eine byte[]. Um bei den Bilddaten, können Sie rufen Sie getRaster()auf der BufferedImage. Dadurch erhalten Sie ein RasterObjekt, das über Methoden für den Zugriff auf die Pixeldaten verfügt (es verfügt über mehrere getPixel()/getPixels() Methoden).

Nachschlagen der API - Dokumentation javax.imageio.ImageIO, java.awt.image.BufferedImage, java.awt.image.Rasterusw.

ImageIO unterstützt standardmäßig eine Reihe von Bildformaten: JPEG, PNG, BMP, WBMP und GIF. Es ist möglich, Unterstützung für weitere Formate hinzuzufügen (Sie benötigen ein Plug-In, das die ImageIO-Dienstanbieterschnittstelle implementiert).

Siehe auch das folgende Tutorial: Arbeiten mit Bildern


16

Für den Fall, dass noch jemand nach einer Lösung ohne Abhängigkeit sucht und wenn Sie eine Datei haben .

1) DataInputStream

 byte[] data = new byte[(int) file.length()];
 DataInputStream dis = new DataInputStream(new FileInputStream(file));
 dis.readFully(data);
 dis.close();

2) ByteArrayOutputStream

 InputStream is = new FileInputStream(file);
 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
 int nRead;
 byte[] data = new byte[(int) file.length()];
 while ((nRead = is.read(data, 0, data.length)) != -1) {
     buffer.write(data, 0, nRead);
 }

3) RandomAccessFile

 RandomAccessFile raf = new RandomAccessFile(file, "r");
 byte[] data = new byte[(int) raf.length()];
 raf.readFully(data);

Was ist, wenn das Byte-Array zu groß ist, was zu OOM für den Heap führen kann? Gibt es eine ähnliche Lösung, die JNI zum Speichern der Bytes verwendet, und später könnten wir inputStream aus den dort gespeicherten Daten verwenden (eine Art temporärer Cache)?
Android-Entwickler

14

Wenn Sie die Apache commons-io-Bibliothek nicht verwenden möchten, stammt dieses Snippet aus der Klasse sun.misc.IOUtils. Es ist fast doppelt so schnell wie die übliche Implementierung mit ByteBuffers:

public static byte[] readFully(InputStream is, int length, boolean readAll)
        throws IOException {
    byte[] output = {};
    if (length == -1) length = Integer.MAX_VALUE;
    int pos = 0;
    while (pos < length) {
        int bytesToRead;
        if (pos >= output.length) { // Only expand when there's no room
            bytesToRead = Math.min(length - pos, output.length + 1024);
            if (output.length < pos + bytesToRead) {
                output = Arrays.copyOf(output, pos + bytesToRead);
            }
        } else {
            bytesToRead = output.length - pos;
        }
        int cc = is.read(output, pos, bytesToRead);
        if (cc < 0) {
            if (readAll && length != Integer.MAX_VALUE) {
                throw new EOFException("Detect premature EOF");
            } else {
                if (output.length != pos) {
                    output = Arrays.copyOf(output, pos);
                }
                break;
            }
        }
        pos += cc;
    }
    return output;
}

Dies ist eine etwas seltsame Lösung. Die Länge ist eine Obergrenze für die Länge des Arrays. Wenn Sie die Länge kennen, brauchen Sie nur: byte [] output = new byte [length]; is.read (Ausgabe); (aber siehe meine Antwort)
Luke Hutchison

@ luke-hutchison wie gesagt, das ist die lösung von sun.misc.IOUtils. In den meisten Fällen kennen Sie die Größe eines InputStreams nicht im Voraus. Wenn also (length == -1) length = Integer.MAX_VALUE; gilt. Diese Lösung funktioniert auch dann, wenn die angegebene Länge größer als die Länge des InputStream ist.
Kristian Kraljic

@LukeHutchison Wenn Sie die Länge kennen, können Sie mit ein paar Zeilen damit umgehen. Wenn Sie sich jede Antwort ansehen, beschweren sich alle, dass die Länge nicht bekannt ist. Schließlich kann eine Standardantwort mit Java 7 Android verwendet werden und benötigt keine externe Bibliothek.
Csaba Toth

11
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (true) {
    int r = in.read(buffer);
    if (r == -1) break;
    out.write(buffer, 0, r);
}

byte[] ret = out.toByteArray();

8

@ Adamski: Sie können Puffer vollständig vermeiden.

Code, der von http://www.exampledepot.com/egs/java.io/File2ByteArray.html kopiert wurde (Ja, er ist sehr ausführlich, benötigt jedoch die halbe Speichergröße wie die andere Lösung.)

// Returns the contents of the file in a byte array.
public static byte[] getBytesFromFile(File file) throws IOException {
    InputStream is = new FileInputStream(file);

    // Get the size of the file
    long length = file.length();

    // You cannot create an array using a long type.
    // It needs to be an int type.
    // Before converting to an int type, check
    // to ensure that file is not larger than Integer.MAX_VALUE.
    if (length > Integer.MAX_VALUE) {
        // File is too large
    }

    // Create the byte array to hold the data
    byte[] bytes = new byte[(int)length];

    // Read in the bytes
    int offset = 0;
    int numRead = 0;
    while (offset < bytes.length
           && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
        offset += numRead;
    }

    // Ensure all the bytes have been read in
    if (offset < bytes.length) {
        throw new IOException("Could not completely read file "+file.getName());
    }

    // Close the input stream and return bytes
    is.close();
    return bytes;
}

5
Kommt darauf an, die Größe im Voraus zu kennen.
Stolsvik

2
Natürlich, aber sie sollten die Größe kennen: "Ich möchte ein Bild lesen"
pihentagy

1
Wenn Sie die Größe kennen, stellt Java den Code für Sie bereit. Siehe meine Antwort oder Google für "DataInputStream" und es ist readFully-Methode.
Dermoritz

Sie sollten hinzufügen, is.close()ob offset < bytes.lengthoder InputStreamwird nicht geschlossen, wenn diese Ausnahme ausgelöst wird.
Jared Rummler

3
Dann besser, Sie sollten versuchen-mit-Ressourcen verwenden
pihentagy

8
Input Stream is ...
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int next = in.read();
while (next > -1) {
    bos.write(next);
    next = in.read();
}
bos.flush();
byte[] result = bos.toByteArray();
bos.close();

Normalerweise puffert das Betriebssystem jedoch bereits genug, um kleinere Dateien nicht zu beunruhigen. Es ist nicht so, dass der Festplattenkopf jedes Byte einzeln liest (eine Festplatte ist eine sich drehende Glasplatte mit magnetisch codierten Informationen, ein bisschen wie das seltsame Symbol, das wir zum Speichern von Daten verwenden: P).
Maarten Bodewes

6
@ Maarten Bodewes: Die meisten Geräte haben eine Art Blockübertragung, so dass nicht jedes read () tatsächlich einen tatsächlichen Gerätezugriff verursacht, aber ein Betriebssystemaufruf pro Byte reicht bereits aus, um die Leistung zu beeinträchtigen. Während die Verpackung InputStreamin einem BufferedInputStreamvor diesem Code würde die OS-Anrufe reduzieren und die Leistung Nachteile deutlich zu mildern, wird dieser Code noch von einem Puffer zum anderen unnötigen manuellen Kopier Arbeit tun.
Holger

4

Java 9 gibt Ihnen endlich eine schöne Methode:

InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();

4
Was ist der Unterschied zwischen diesem und InputStram.readAllBytes()jenem Einzeiler?
Slava Semushin

2

Ich weiß, dass es zu spät ist, aber hier denke ich, ist eine sauberere Lösung, die besser lesbar ist ...

/**
 * method converts {@link InputStream} Object into byte[] array.
 * 
 * @param stream the {@link InputStream} Object.
 * @return the byte[] array representation of received {@link InputStream} Object.
 * @throws IOException if an error occurs.
 */
public static byte[] streamToByteArray(InputStream stream) throws IOException {

    byte[] buffer = new byte[1024];
    ByteArrayOutputStream os = new ByteArrayOutputStream();

    int line = 0;
    // read bytes from stream, and store them in buffer
    while ((line = stream.read(buffer)) != -1) {
        // Writes bytes from byte array (buffer) into output stream.
        os.write(buffer, 0, line);
    }
    stream.close();
    os.flush();
    os.close();
    return os.toByteArray();
}

4
Sie sollten Try-with-Resources verwenden.
Victor Stafusa

Das Aufräumen am Ende muss im Fehlerfall in einem endgültigen Block erfolgen, da dies sonst zu einem Speicherverlust führen kann.
MGDavies

2

Java 8 Way (danke an BufferedReader und Adam Bien )

private static byte[] readFully(InputStream input) throws IOException {
    try (BufferedReader buffer = new BufferedReader(new InputStreamReader(input))) {
        return buffer.lines().collect(Collectors.joining("\n")).getBytes(<charset_can_be_specified>);
    }
}

Beachten Sie, dass diese Lösung den Wagenrücklauf ('\ r') löscht und unangemessen sein kann.


4
Das ist für String. OP bittet um byte[].
FrozenFire

Es könnte nicht nur \rein Problem sein. Diese Methode konvertiert die Bytes in Zeichen und wieder zurück (unter Verwendung des Standardzeichensatzes für InputStreamReader). Alle Bytes, die in der Standardzeichencodierung nicht gültig sind (z. B. -1 für UTF-8 unter Linux), werden beschädigt, wodurch möglicherweise sogar die Anzahl der Bytes geändert wird.
Seanf

Dies scheint eine gute Antwort zu sein, ist aber textorientiert. Käufer aufgepasst.
Wheezil

1

Ich habe versucht, die Antwort von @ numan mit einem Fix zum Schreiben von Mülldaten zu bearbeiten, aber die Bearbeitung wurde abgelehnt. Obwohl dieser kurze Code nichts Brillantes ist, kann ich keine bessere Antwort finden. Folgendes macht für mich am meisten Sinn:

ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024]; // you can configure the buffer size
int length;

while ((length = in.read(buffer)) != -1) out.write(buffer, 0, length); //copy streams
in.close(); // call this in a finally block

byte[] result = out.toByteArray();

Übrigens muss ByteArrayOutputStream nicht geschlossen werden. try / finally-Konstrukte wurden aus Gründen der Lesbarkeit weggelassen


1

Siehe die InputStream.available()Dokumentation:

Es ist besonders wichtig zu wissen, dass Sie diese Methode nicht verwenden dürfen, um die Größe eines Containers zu bestimmen, und davon auszugehen, dass Sie den gesamten Stream lesen können, ohne die Größe des Containers ändern zu müssen. Solche Aufrufer sollten wahrscheinlich alles, was sie lesen, in einen ByteArrayOutputStream schreiben und diesen in ein Byte-Array konvertieren. Wenn Sie alternativ aus einer Datei lesen, gibt File.length die aktuelle Länge der Datei zurück (obwohl die Annahme, dass sich die Länge der Datei nicht ändern kann, möglicherweise falsch ist, ist das Lesen einer Datei von Natur aus rassig).


1

Wickeln Sie es in einen DataInputStream ein, wenn dies aus irgendeinem Grund vom Tisch ist. Verwenden Sie einfach read, um darauf zu hämmern, bis Sie -1 oder den gesamten Block erhalten, nach dem Sie gefragt haben.

public int readFully(InputStream in, byte[] data) throws IOException {
    int offset = 0;
    int bytesRead;
    boolean read = false;
    while ((bytesRead = in.read(data, offset, data.length - offset)) != -1) {
        read = true;
        offset += bytesRead;
        if (offset >= data.length) {
            break;
        }
    }
    return (read) ? offset : -1;
}

1

Bei einigen AWS-Transaktionen tritt eine gewisse Verzögerung auf, während das S3-Objekt in ByteArray konvertiert wird.

Hinweis: S3-Objekt ist ein PDF-Dokument (maximale Größe 3 MB).

Wir verwenden die Option 1 (org.apache.commons.io.IOUtils), um das S3-Objekt in ByteArray zu konvertieren. Wir haben festgestellt, dass S3 die eingebaute IOUtils-Methode zum Konvertieren des S3-Objekts in ByteArray bereitstellt. Wir bitten Sie, zu bestätigen, wie das S3-Objekt am besten in ByteArray konvertiert werden kann, um die Verzögerung zu vermeiden.

Option 1:

import org.apache.commons.io.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);

Option 2:

import com.amazonaws.util.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);

Lassen Sie mich auch wissen, ob wir eine andere bessere Möglichkeit haben, das s3-Objekt in Bytearray zu konvertieren


0

Der andere Fall, um das richtige Byte-Array über den Stream zu erhalten, nachdem die Anforderung an den Server gesendet und auf die Antwort gewartet wurde.

/**
         * Begin setup TCP connection to PC app
         * to open integrate connection between mobile app and pc app (or mobile app)
         */
        mSocket = new Socket(IP, port);
       // mSocket.setSoTimeout(30000);

        DataOutputStream mDos = new DataOutputStream(mSocket.getOutputStream());

        String str = "MobileRequest#" + params[0] + "#<EOF>";

        mDos.write(str.getBytes());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        /* Since data are accepted as byte, all of them will be collected in the
        following byte array which initialised with accepted data length. */
        DataInputStream mDis = new DataInputStream(mSocket.getInputStream());
        byte[] data = new byte[mDis.available()];

        // Collecting data into byte array
        for (int i = 0; i < data.length; i++)
            data[i] = mDis.readByte();

        // Converting collected data in byte array into String.
        String RESPONSE = new String(data);

0

Sie erstellen eine zusätzliche Kopie, wenn Sie ByteArrayOutputStream verwenden. Wenn Sie die Länge des Streams kennen, bevor Sie mit dem Lesen beginnen (z. B. ist der InputStream tatsächlich ein FileInputStream, und Sie können file.length () für die Datei aufrufen, oder der InputStream ist ein Zipfile-Eintrag InputStream, und Sie können zipEntry aufrufen. length ()), dann ist es weitaus besser, direkt in das byte [] -Array zu schreiben - es verbraucht die Hälfte des Speichers und spart Zeit.

// Read the file contents into a byte[] array
byte[] buf = new byte[inputStreamLength];
int bytesRead = Math.max(0, inputStream.read(buf));

// If needed: for safety, truncate the array if the file may somehow get
// truncated during the read operation
byte[] contents = bytesRead == inputStreamLength ? buf
                  : Arrays.copyOf(buf, bytesRead);

Hinweis: Die letzte Zeile oben befasst sich mit Dateien, die während des Lesens des Streams abgeschnitten werden. Wenn Sie diese Möglichkeit nutzen müssen, aber wenn die Datei während des Lesens des Streams länger wird, wird der Inhalt im Array byte [] nicht verlängert Um den neuen Dateiinhalt einzuschließen , wird das Array einfach auf die alte Länge inputStreamLength gekürzt .


0

Ich benutze das.

public static byte[] toByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        try {
            byte[] b = new byte[4096];
            int n = 0;
            while ((n = is.read(b)) != -1) {
                output.write(b, 0, n);
            }
            return output.toByteArray();
        } finally {
            output.close();
        }
    }

2
Fügen Sie eine Erklärung mit Antwort hinzu, wie diese Antwort OP bei der Behebung des aktuellen Problems
hilft

0

Dies ist meine Copy-Paste-Version:

@SuppressWarnings("empty-statement")
public static byte[] inputStreamToByte(InputStream is) throws IOException {
    if (is == null) {
        return null;
    }
    // Define a size if you have an idea of it.
    ByteArrayOutputStream r = new ByteArrayOutputStream(2048);
    byte[] read = new byte[512]; // Your buffer size.
    for (int i; -1 != (i = is.read(read)); r.write(read, 0, i));
    is.close();
    return r.toByteArray();
}

2
Während dieses Code-Snippet die Frage lösen kann, hilft eine Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen.
Ferrybig

0

Java 7 und höher:

import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);

20
sun.misc.IOUtilsist nicht "Java 7". Es handelt sich um eine proprietäre, implementierungsspezifische Klasse, die in anderen JRE-Implementierungen möglicherweise nicht vorhanden ist und in einer der nächsten Versionen ohne Vorwarnung verschwinden kann.
Holger


0

Hier ist eine optimierte Version, die versucht, das Kopieren von Datenbytes so weit wie möglich zu vermeiden:

private static byte[] loadStream (InputStream stream) throws IOException {
   int available = stream.available();
   int expectedSize = available > 0 ? available : -1;
   return loadStream(stream, expectedSize);
}

private static byte[] loadStream (InputStream stream, int expectedSize) throws IOException {
   int basicBufferSize = 0x4000;
   int initialBufferSize = (expectedSize >= 0) ? expectedSize : basicBufferSize;
   byte[] buf = new byte[initialBufferSize];
   int pos = 0;
   while (true) {
      if (pos == buf.length) {
         int readAhead = -1;
         if (pos == expectedSize) {
            readAhead = stream.read();       // test whether EOF is at expectedSize
            if (readAhead == -1) {
               return buf;
            }
         }
         int newBufferSize = Math.max(2 * buf.length, basicBufferSize);
         buf = Arrays.copyOf(buf, newBufferSize);
         if (readAhead != -1) {
            buf[pos++] = (byte)readAhead;
         }
      }
      int len = stream.read(buf, pos, buf.length - pos);
      if (len < 0) {
         return Arrays.copyOf(buf, pos);
      }
      pos += len;
   }
}

0

Lösung in Kotlin (funktioniert natürlich auch in Java), die beide Fälle umfasst, in denen Sie die Größe kennen oder nicht:

    fun InputStream.readBytesWithSize(size: Long): ByteArray? {
        return when {
            size < 0L -> this.readBytes()
            size == 0L -> ByteArray(0)
            size > Int.MAX_VALUE -> null
            else -> {
                val sizeInt = size.toInt()
                val result = ByteArray(sizeInt)
                readBytesIntoByteArray(result, sizeInt)
                result
            }
        }
    }

    fun InputStream.readBytesIntoByteArray(byteArray: ByteArray,bytesToRead:Int=byteArray.size) {
        var offset = 0
        while (true) {
            val read = this.read(byteArray, offset, bytesToRead - offset)
            if (read == -1)
                break
            offset += read
            if (offset >= bytesToRead)
                break
        }
    }

Wenn Sie die Größe kennen, sparen Sie doppelt so viel Speicher wie bei den anderen Lösungen (in einem kurzen Moment, aber dennoch nützlich). Das liegt daran, dass Sie den gesamten Stream bis zum Ende lesen und dann in ein Byte-Array konvertieren müssen (ähnlich wie ArrayList, das Sie nur in ein Array konvertieren).

Wenn Sie beispielsweise mit Android arbeiten und etwas Uri zu handhaben haben, können Sie versuchen, die Größe folgendermaßen zu ermitteln:

    fun getStreamLengthFromUri(context: Context, uri: Uri): Long {
        context.contentResolver.query(uri, arrayOf(MediaStore.MediaColumns.SIZE), null, null, null)?.use {
            if (!it.moveToNext())
                return@use
            val fileSize = it.getLong(it.getColumnIndex(MediaStore.MediaColumns.SIZE))
            if (fileSize > 0)
                return fileSize
        }
        //if you wish, you can also get the file-path from the uri here, and then try to get its size, using this: https://stackoverflow.com/a/61835665/878126
        FileUtilEx.getFilePathFromUri(context, uri, false)?.use {
            val file = it.file
            val fileSize = file.length()
            if (fileSize > 0)
                return fileSize
        }
        context.contentResolver.openInputStream(uri)?.use { inputStream ->
            if (inputStream is FileInputStream)
                return inputStream.channel.size()
            else {
                var bytesCount = 0L
                while (true) {
                    val available = inputStream.available()
                    if (available == 0)
                        break
                    val skip = inputStream.skip(available.toLong())
                    if (skip < 0)
                        break
                    bytesCount += skip
                }
                if (bytesCount > 0L)
                    return bytesCount
            }
        }
        return -1L
    }

-1
/*InputStream class_InputStream = null;
I am reading class from DB 
class_InputStream = rs.getBinaryStream(1);
Your Input stream could be from any source
*/
int thisLine;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((thisLine = class_InputStream.read()) != -1) {
    bos.write(thisLine);
}
bos.flush();
byte [] yourBytes = bos.toByteArray();

/*Don't forget in the finally block to close ByteArrayOutputStream & InputStream
 In my case the IS is from resultset so just closing the rs will do it*/

if (bos != null){
    bos.close();
}

Das Schließen und Spülen von Bos ist eine Verschwendung von Tastaturklicks. Das Schließen des Eingabestreams hilft eher. Das Lesen von jeweils einem Byte ist ineffizient. Siehe numans Antwort.
Akostadinov
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.