Konversi InputStream ke byte array di Java

Jawaban:

1136

Anda dapat menggunakan Apache Commons IO untuk menangani ini dan tugas serupa.

The IOUtilsjenis memiliki metode statis untuk membaca InputStreamdan mengembalikan byte[].

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

Secara internal ini membuat ByteArrayOutputStreamdan menyalin byte ke output, lalu memanggil toByteArray(). Ini menangani file besar dengan menyalin byte dalam blok 4KiB.

Penjual Kaya
sumber
188
Untuk yang ingin menulis 4 baris kode, Anda berpikir bahwa mengimpor dependensi pihak ketiga bermanfaat?
oxbow_lakes
217
Jika ada perpustakaan yang menangani persyaratan, dan berkaitan dengan pemrosesan untuk file besar, dan sudah teruji dengan baik, tentu pertanyaannya adalah mengapa saya menulisnya sendiri? Toples hanya 107KB dan jika Anda memerlukan satu metode dari itu, Anda kemungkinan akan menggunakan yang lain juga
Penjual Kaya
242
@oxbow_lakes: mengingat jumlah implementasi salah yang mengejutkan dari fitur ini yang pernah saya lihat dalam kehidupan pengembang saya, saya merasa ya itu sangat layak untuk ketergantungan eksternal untuk memperbaikinya.
Joachim Sauer
17
Mengapa tidak pergi dan melihat-lihat hal-hal seperti Apache commons FastArrayListatau Peta referensi lunak & lemah mereka dan kembali untuk memberi tahu saya seberapa "teruji" perpustakaan ini. Ini tumpukan sampah
oxbow_lakes
87
Selain Apache commons-io, periksa kelas ByteStreams dari Google Guava . InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
michaelok
446

Anda perlu membaca setiap byte dari Anda InputStreamdan menulisnya ke a ByteArrayOutputStream.

Anda kemudian dapat mengambil array byte yang mendasarinya dengan memanggil 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();
Adamski
sumber
17
Bagaimana dengan ukuran byte yang baru dibuat []. Mengapa 16384? Bagaimana saya bisa menentukan ukuran tepat yang tepat? Terima kasih banyak.
Ondrej Bozek
6
16384 adalah pilihan yang cukup sewenang-wenang meskipun saya cenderung mendukung kekuatan 2 untuk meningkatkan peluang array menyelaraskan dengan batas kata. Jawaban pihentagy menunjukkan bagaimana Anda dapat menghindari penggunaan buffer perantara, tetapi mengalokasikan array dengan ukuran yang benar. Kecuali jika Anda berurusan dengan file besar, saya pribadi lebih suka kode di atas, yang lebih elegan dan dapat digunakan untuk InputStreams di mana jumlah byte untuk dibaca tidak diketahui sebelumnya.
Adamski
@ Adamski Bukankah menciptakan array byte jauh lebih besar daripada yang Anda harapkan akan ada di stream, membuang-buang memori?
Paul Brewczynski
@ Benlu: Ya itu benar. Namun, dalam contoh saya array byte hanya 16Kb dan sangat kecil menurut standar saat ini. Juga, tentu saja memori ini akan dibebaskan lagi sesudahnya.
Adamski
5
@Adamski Banyak infrastruktur perangkat keras, server web, dan komponen lapisan OS menggunakan buffer 4K untuk memindahkan data, jadi itulah alasan untuk angka pastinya, tetapi poin utamanya adalah Anda mendapatkan sedikit peningkatan kinerja dengan melampaui 4K bahwa itu umumnya dianggap boros memori. Saya berasumsi ini masih benar, karena ini adalah pengetahuan lama yang saya miliki!
132

Gunakan vanilla Java's DataInputStreamdan readFullyMetodenya (setidaknya ada sejak Java 1.4):

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

Ada beberapa rasa lain dari metode ini, tetapi saya menggunakan ini sepanjang waktu untuk use case ini.

dermoritz
sumber
45
+1 untuk menggunakan perpustakaan standar alih-alih ketergantungan pihak ke-3. Sayangnya itu tidak berfungsi untuk saya karena saya tidak tahu panjang aliran di muka.
Andrew Spencer
2
apa itu imgFile? Itu tidak bisa menjadi InputStream, yang seharusnya menjadi input dari metode ini
Janus Troelsen
4
@janus itu adalah "File". cara ini hanya berfungsi jika Anda mengetahui panjang file atau jumlah byte yang harus dibaca.
dermoritz
5
Hal yang menarik, tetapi Anda harus tahu panjang yang tepat dari (bagian dari) aliran untuk membaca. Selain itu, kelas DataInputStreamadalah primer yang digunakan untuk membaca tipe primer (Longs, Shorts, Chars ...) dari aliran, sehingga kita dapat melihat penggunaan ini sebagai penyalahgunaan kelas.
Olivier Faucheux
17
Jika Anda sudah tahu panjang data untuk dibaca dari arus, ini tidak lebih baik dari itu InputStream.read.
Logan Pickup
119

Jika Anda menggunakan google jambu , ini akan sesederhana:

byte[] bytes = ByteStreams.toByteArray(inputStream);
bertie
sumber
8
ByteStreamsdijelaskan dengan@Beta
Kid101
46

Seperti biasa, juga kerangka Pegas (pegas-inti sejak 3.2.2) memiliki sesuatu untuk Anda:StreamUtils.copyToByteArray()

Arne Burmeister
sumber
Seperti kebanyakan orang lain, saya ingin menghindari menggunakan perpustakaan pihak ke-3 untuk sesuatu yang sangat sederhana, tetapi Java 9 bukan pilihan saat ini ... untungnya, saya sudah menggunakan Spring.
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();
}
oliverkn
sumber
2
Ini adalah contoh dan dengan demikian, singkatnya adalah urutan hari. Juga mengembalikan nol di sini akan menjadi pilihan yang tepat dalam beberapa kasus (meskipun dalam lingkungan produksi Anda juga akan memiliki penanganan dan dokumentasi pengecualian yang tepat).
11
Saya memahami singkatnya dalam sebuah contoh, tetapi mengapa tidak hanya membuat metode contoh melempar IOException daripada menelannya dan mengembalikan nilai yang tidak berarti?
pendor
4
Saya telah mengambil kebebasan untuk berubah dari 'return null' ke 'throw IOException'
kritzikratzi
3
Try-with-resources tidak diperlukan di sini, karena ByteArrayOutputStream # close () tidak melakukan apa-apa. (ByteArrayOutputStream # flush () tidak diperlukan dan tidak melakukan apa-apa juga.)
Luke Hutchison
25

Solusi aman (dengan kemampuanclosestream dengan benar):

  • Versi Java 9+:

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

    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);
            }
        }
    }
  • Versi Kotlin (ketika Java 9+ tidak dapat diakses):

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

    Untuk menghindari bersarang uselihat di sini .

Mir-Ismaili
sumber
Bukankah itu berarti bahwa pada titik tertentu Anda akan menggunakan memori yang berlipat ganda, karena Anda memiliki buffer dan array byte? Apakah tidak ada cara untuk mengirim byte secara langsung ke array byte keluaran?
pengembang android
@androiddeveloper; Maafkan saya. Saya tidak tahu jawabannya! Tapi saya rasa tidak. Saya pikir cara ini (menggunakan buffer) adalah cara yang dioptimalkan.
Mir-Ismaili
Saya sudah memeriksanya, tetapi sepertinya itu satu-satunya solusi yang dapat Anda pilih ketika Anda tidak tahu ukurannya. Jika Anda sudah tahu ukurannya, Anda bisa langsung membuat byte-array dengan ukuran yang diberikan dan mengisinya. Jadi, Anda menggunakan fungsi yang akan mendapatkan parameter ukuran byte, dan jika valid, gunakan untuk langsung membuat dan mengisi array byte, tanpa membuat objek besar lainnya.
pengembang android
@androiddeveloper; Terima kasih atas informasi anda. Saya tidak kenal mereka.
Mir-Ismaili
19

Apakah Anda benar-benar membutuhkan gambar sebagai byte[]? Apa tepatnya yang Anda harapkan di Internet?byte[] - konten lengkap file gambar, yang dikodekan dalam format apa pun file gambar, atau nilai-nilai piksel RGB?

Jawaban lain di sini menunjukkan kepada Anda cara membaca file ke dalam byte[]. Anda byte[]akan berisi konten file yang tepat, dan Anda harus men-decode itu untuk melakukan apa saja dengan data gambar.

API standar Java untuk membaca (dan menulis) gambar adalah API ImageIO, yang dapat Anda temukan dalam paket javax.imageio. Anda dapat membaca dalam gambar dari file hanya dengan satu baris kode:

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

Ini akan memberi Anda BufferedImage, bukan a byte[]. Untuk mendapatkan data gambar, Anda dapat menghubungi getRaster()di BufferedImage. Ini akan memberi Anda Rasterobjek, yang memiliki metode untuk mengakses data pixel (memiliki beberapa getPixel()/getPixels() metode).

Lookup dokumentasi API untuk javax.imageio.ImageIO, java.awt.image.BufferedImage, java.awt.image.Rasterdll

ImageIO mendukung sejumlah format gambar secara default: JPEG, PNG, BMP, WBMP dan GIF. Dimungkinkan untuk menambahkan dukungan untuk lebih banyak format (Anda memerlukan plug-in yang mengimplementasikan antarmuka penyedia layanan ImageIO).

Lihat juga tutorial berikut: Bekerja dengan Gambar

Jesper
sumber
16

Dalam kasus seseorang masih mencari solusi tanpa ketergantungan dan Jika Anda memiliki file .

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);
harsh_v
sumber
Katakanlah, bagaimana jika array byte terlalu besar yang dapat menyebabkan OOM untuk heap? Apakah ada solusi serupa yang akan menggunakan JNI untuk menyimpan byte, dan nantinya kita akan dapat menggunakan inputStream dari data yang disimpan di sana (semacam cache sementara)?
pengembang android
14

Jika Anda tidak ingin menggunakan pustaka Apache commons-io, cuplikan ini diambil dari kelas sun.misc.IOUtils. Ini hampir dua kali lebih cepat dari implementasi umum menggunakan 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;
}
Kristian Kraljic
sumber
Ini sedikit solusi aneh, panjang adalah batas atas pada panjang array. Jika Anda tahu panjangnya, yang Anda butuhkan adalah: byte [] output = byte baru [panjang]; is.read (output); (tapi lihat jawaban saya)
Luke Hutchison
@ luke-hutchison seperti yang saya katakan, ini adalah solusi dari sun.misc.IOUtils. Dalam kasus yang paling umum Anda tidak tahu ukuran dimuka InputStream, jadi jika (length == -1) length = Integer.MAX_VALUE; berlaku. Solusi ini berfungsi, bahkan jika panjang yang diberikan lebih besar dari panjang InputStream.
Kristian Kraljic
@LukeHutchison Jika Anda tahu panjangnya, Anda bisa mengatasinya dengan beberapa baris. Jika Anda melihat setiap jawaban, semua orang mengeluh bahwa panjangnya tidak diketahui. Akhirnya jawaban yang standar, dapat digunakan dengan Java 7 Android, dan tidak memerlukan perpustakaan eksternal.
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();
YulCheney
sumber
8

@Adamski: Anda dapat menghindari buffer sepenuhnya.

Kode disalin dari http://www.exampledepot.com/egs/java.io/File2ByteArray.html (Ya, sangat verbose, tetapi membutuhkan setengah ukuran memori sebagai solusi lain.)

// 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;
}
pihentagy
sumber
5
Tergantung pada mengetahui ukuran dimuka.
stolsvik
2
Tentu saja, tetapi mereka harus tahu ukurannya: "Saya ingin membaca gambar"
pihentagy
1
jika Anda tahu ukurannya, maka java menyediakan kode untuk Anda. lihat jawaban saya atau google untuk "DataInputStream" dan metode readFully.
dermoritz
Anda harus menambahkan is.close()jika offset < bytes.lengthatau InputStreamtidak akan ditutup jika pengecualian itu dilemparkan.
Jared Rummler
3
Maka lebih baik, Anda harus menggunakan coba-dengan-sumber daya
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();
Aturio
sumber
Namun, biasanya OS sudah buffer cukup untuk ini tidak menjadi masalah besar untuk file yang lebih kecil. Ini tidak seperti kepala hard disk akan membaca setiap byte secara terpisah (hard disk adalah pelat kaca pembalik dengan informasi kode magnetik di atasnya, agak seperti ikon aneh yang kita gunakan untuk menyimpan data: P).
Maarten Bodewes
6
@ Maarten Bodewes: sebagian besar perangkat memiliki semacam transfer blok, jadi tidak setiap read () akan menyebabkan akses perangkat yang sebenarnya, memang, tetapi memiliki panggilan OS per byte sudah cukup untuk mematikan kinerja. Sementara membungkus InputStreamdalam BufferedInputStreamsebelum kode yang akan mengurangi OS-panggilan dan mengurangi kelemahan kinerja secara signifikan, kode yang masih akan melakukan yang tidak perlu kerja menyalin pengguna dari satu buffer yang lain.
Holger
4

Java 9 akhirnya akan memberi Anda metode yang bagus:

InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
Christian Ullenboom
sumber
4
Apa perbedaan antara ini dan InputStram.readAllBytes()itu satu garis ?
Slava Semushin
2

Saya tahu sudah terlambat tetapi di sini saya pikir ini adalah solusi bersih yang lebih mudah dibaca ...

/**
 * 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();
}
Solusi Sederhana
sumber
4
Anda harus menggunakan coba-dengan-sumber daya.
Victor Stafusa
Merapikan pada akhirnya harus dilakukan di blok akhirnya jika terjadi kesalahan, jika tidak, ini dapat menyebabkan kebocoran memori.
MGDavies
2

Java 8 way (terima kasih kepada BufferedReader dan 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>);
    }
}

Perhatikan bahwa solusi ini menghapus carriage return ('\ r') dan dapat menjadi tidak tepat.

Ilya Bystrov
sumber
4
Itu untuk String. OP meminta byte[].
FrozenFire
Bukan hanya \ritu yang bisa menjadi masalah. Metode ini mengubah byte ke karakter dan kembali lagi (menggunakan karakter default yang ditetapkan untuk InputStreamReader). Setiap byte yang tidak valid dalam pengkodean karakter default (katakanlah, -1 untuk UTF-8 di Linux) akan rusak, bahkan berpotensi mengubah jumlah byte.
seanf
Sepertinya ini jawaban yang bagus, tapi berorientasi teks. Hati-hati pembeli.
Wheezil
1

Saya mencoba mengedit jawaban @ numan dengan perbaikan untuk menulis data sampah tetapi edit ditolak. Sementara potongan pendek kode ini tidak brilian, saya tidak bisa melihat jawaban lain yang lebih baik. Inilah yang paling masuk akal bagi saya:

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

btw ByteArrayOutputStream tidak perlu ditutup. coba / akhirnya konstruk dihilangkan agar mudah dibaca

akostadinov
sumber
1

Lihat InputStream.available()dokumentasi:

Sangat penting untuk menyadari bahwa Anda tidak boleh menggunakan metode ini untuk mengukur ukuran wadah dan menganggap bahwa Anda dapat membaca keseluruhan aliran tanpa perlu mengubah ukuran wadah. Penelepon semacam itu mungkin harus menulis semua yang mereka baca ke ByteArrayOutputStream dan mengonversinya menjadi array byte. Atau, jika Anda membaca dari file, File.length mengembalikan panjang file saat ini (meskipun dengan asumsi panjang file tidak dapat berubah mungkin salah, membaca file secara inheren bersemangat).

yichouangle
sumber
1

Bungkus dalam DataInputStream jika itu ada di luar meja untuk beberapa alasan, cukup gunakan baca untuk palu di atasnya sampai memberi Anda -1 atau seluruh blok yang Anda minta.

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;
}
Tatarize
sumber
1

Kami melihat beberapa keterlambatan untuk beberapa transaksi AWS, saat mengonversi objek S3 ke ByteArray.

Catatan: Objek S3 adalah dokumen PDF (ukuran maksimal adalah 3 mb).

Kami menggunakan opsi # 1 (org.apache.commons.io.IOUtils) untuk mengonversi objek S3 ke ByteArray. Kami telah memperhatikan S3 menyediakan metode IOUtils inbuild untuk mengubah objek S3 menjadi ByteArray, kami meminta Anda untuk mengonfirmasi apa cara terbaik untuk mengonversi objek S3 ke ByteArray untuk menghindari keterlambatan.

Pilihan 1:

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

Pilihan 2:

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

Juga beri tahu saya jika kami memiliki cara lain yang lebih baik untuk mengonversi objek s3 menjadi bytearray

Bharathiraja S
sumber
0

Kasus lain untuk mendapatkan byte array yang benar melalui aliran, setelah mengirim permintaan ke server dan menunggu respons.

/**
         * 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);
Menara Huy
sumber
0

Anda sedang melakukan salinan tambahan jika Anda menggunakan ByteArrayOutputStream. Jika Anda mengetahui panjang aliran sebelum Anda mulai membacanya (mis. InputStream sebenarnya adalah FileInputStream, dan Anda dapat memanggil file.length () pada file, atau InputStream adalah entri zipfile, InputStream, dan Anda dapat memanggil zipEntry. length ()), maka jauh lebih baik untuk menulis langsung ke array byte [] - ia menggunakan setengah memori, dan menghemat waktu.

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

NB baris terakhir di atas berkaitan dengan file yang terpotong saat stream sedang dibaca, jika Anda perlu menangani kemungkinan itu, tetapi jika file menjadi lebih lama saat stream sedang dibaca, konten dalam array byte [] tidak akan diperpanjang untuk memasukkan konten file baru, array hanya akan dipotong ke inputStreamLength panjang lama .

Luke Hutchison
sumber
0

Saya menggunakan ini.

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();
        }
    }
cchcc
sumber
2
Tambahkan beberapa penjelasan dengan jawaban untuk bagaimana jawaban ini membantu OP dalam memperbaiki masalah saat ini
ρяσѕρєя K
0

Ini adalah versi salin-tempel saya:

@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();
}
Daniel De León
sumber
2
Sementara potongan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda.
Ferrybig
0

Java 7 dan yang lebih baru:

import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
Antonio
sumber
20
sun.misc.IOUtilsbukan "Java 7". Ini adalah kelas khusus, implementasi khusus yang mungkin tidak ada dalam implementasi JRE lain dan dapat menghilang tanpa peringatan di salah satu rilis berikutnya.
Holger
0

Anda dapat mencoba Cactoos :

byte[] array = new BytesOf(stream).bytes();
yegor256
sumber
0

Ini adalah versi yang dioptimalkan, yang berusaha menghindari menyalin byte data sebanyak mungkin:

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;
   }
}
Christian d'Heureuse
sumber
0

Solusi di Kotlin (tentu saja akan bekerja di Jawa), yang mencakup kedua kasus ketika Anda mengetahui ukurannya atau tidak:

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

Jika Anda tahu ukurannya, itu menghemat Anda memiliki dua kali lipat memori yang digunakan dibandingkan dengan solusi lain (dalam waktu singkat, tetapi masih bisa bermanfaat). Itu karena Anda harus membaca seluruh aliran hingga akhir, dan kemudian mengonversinya menjadi array byte (mirip dengan ArrayList yang Anda konversi menjadi hanya array).

Jadi, jika Anda menggunakan Android, misalnya, dan Anda dapat menangani beberapa Uri, Anda dapat mencoba untuk mendapatkan ukuran menggunakan ini:

    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
    }
pengembang android
sumber
-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();
}
Madhu
sumber
Menutup dan memerah bos adalah buang-buang klik keyboard. Menutup aliran input lebih mungkin membantu. Membaca satu byte pada suatu waktu tidak efisien. Lihat jawaban numan.
akostadinov