Java'da InputStream'i bayt dizisine dönüştürme


Yanıtlar:


1135

Bu ve benzeri görevleri yerine getirmek için Apache Commons IO'yu kullanabilirsiniz .

IOUtilsTip bir okumak için statik yöntem vardır InputStreamve bir dönüş byte[].

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

Dahili olarak bu bir a oluşturur ByteArrayOutputStreamve baytları çıktıya kopyalar, sonra çağırır toByteArray(). 4KiB bloklarındaki baytları kopyalayarak büyük dosyaları işler.


188
4 satır kod yazmak için, bir üçüncü taraf bağımlılığını içe aktarmanın faydalı olduğunu mu düşünüyorsunuz?
oxbow_lakes

217
Gereksinimi karşılayan ve büyük dosyaların işlenmesini ele alan ve iyi test edilmiş bir kütüphane varsa, kesinlikle soru neden kendim yazmalıyım? Kavanoz sadece 107KB'dir ve ondan bir yönteme ihtiyacınız varsa, başkalarını da kullanmanız olasıdır
Zengin Satıcı

242
@oxbow_lakes: ait şaşırtıcı miktarı göz önüne alındığında yanlış benim geliştirici hayatta gördüğüm bu özelliğin uygulamaları, bunu hissetmek evet öyle çok fazla değer doğru olsun dış bağımlılığı.
Joachim Sauer

17
Neden gidip Apache FastArrayListmüşterileri gibi şeyler ve onların yumuşak ve zayıf referans Haritalar bir göz atın ve bana bu kütüphane ne kadar "iyi test edilmiş" söylemek için geri gelmek. Çöp yığını
oxbow_lakes

87
Apache commons- io'ya ek olarak , Google Guava'dan ByteStreams sınıfına göz atın . InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
michaelok

446

Her bir baytı kendinizden okumalı InputStreamve a yazmalısınız ByteArrayOutputStream.

Ardından, alttaki bayt dizisini arayarak alabilirsiniz 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
Yeni oluşturulan baytın boyutu [] ne olacak? Neden 16384? Tam doğru boyutu nasıl belirleyebilirim? Çok teşekkür ederim.
Ondrej Bozek

6
16384 oldukça keyfi bir seçim olsa da dizinin sözcük sınırlarıyla hizalanma şansını artırmak için 2 gücünden yana olma eğilimindeyim. pihentagy'nin cevabı, ara bir arabellek kullanmaktan nasıl kaçınabileceğinizi değil, doğru boyutta bir dizi ayırabileceğinizi gösterir. Büyük dosyalarla uğraşmadıkça, yukarıdaki kodu şahsen tercih ederim, bu daha zariftir ve okunacak bayt sayısının önceden bilinmediği InputStreams için kullanılabilir.
Adamski

@Adamski Veri akışında olmasını beklediğinizden daha büyük bayt dizisi oluşturmuyor, hafızayı boşa harcıyor mu?
Paul Brewczynski

@ bluesm: Evet doğru. Ancak, benim örneğimde bayt dizisi sadece 16Kb ve günümüz standartlarına göre çok küçük. Ayrıca, elbette bu bellek daha sonra tekrar serbest bırakılacak.
Adamski

5
@Adamski Çok sayıda altyapı donanımı, web sunucusu ve OS katmanı bileşeni verileri taşımak için 4K tamponlar kullanıyor, bu yüzden tam sayının nedeni bu, ancak asıl nokta 4K'yı geçerek bu kadar az performans artışı elde etmeniz. genellikle bellek israfı olarak kabul edilir. Bunun hala doğru olduğunu varsayıyorum , çünkü on yıllık bilgim var!


132

Vanilya Java'sını DataInputStreamve readFullyYöntemini kullanın (en azından Java 1.4'ten beri var):

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

Bu yöntemin başka lezzetleri de var, ama bunu her zaman bu kullanım durumu için kullanıyorum.


45
Üçüncü taraf bağımlılığı yerine standart kitaplıkları kullanmak için +1. Ne yazık ki benim için işe yaramıyor çünkü dere akışının uzunluğunu bilmiyorum.
Andrew Spencer

2
imgFile nedir? Bu yöntemin girdisi olması gereken bir InputStream olamaz
Janus Troelsen

4
@janus bir "Dosya" dır. Bu şekilde yalnızca dosyanın uzunluğunu veya okunacak bayt sayısını biliyorsanız çalışır.
dermoritz

5
İlginç bir şey, ancak okunacak akışın (bir kısmının) tam uzunluğunu bilmelisiniz. Dahası, sınıf DataInputStreambirincil olarak bir akıştan birincil türleri (Uzunlar, Kısalar, Karakterler ...) okumak için kullanılır, bu nedenle bu kullanımı sınıfın yanlış kullanımı olarak görebiliriz.
Olivier Faucheux

17
Akıştan okunacak verilerin uzunluğunu zaten biliyorsanız, bu bundan daha iyi değildir InputStream.read.
Logan Pickup

119

Google guava'yı kullanırsanız , bu kadar basit olacaktır:

byte[] bytes = ByteStreams.toByteArray(inputStream);

8
ByteStreamsile açıklama eklendi@Beta
Kid101

46

Her zaman olduğu gibi, Bahar çerçevesinin de (3.2.2'den beri bahar çekirdeği) sizin için bir şeyleri var:StreamUtils.copyToByteArray()


Diğerleri gibi, ben de çok basit bir şey için 3. parti kitaplık kullanmaktan kaçınmak istedim, ama Java 9 şu anda bir seçenek değil ... neyse ki, zaten Spring kullanıyordum.
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
Bu bir örnektir ve bu nedenle kısalık günün sırasıdır. Ayrıca burada null döndürmek bazı durumlarda uygun seçim olacaktır (bir üretim ortamında da uygun istisna işleme ve dokümantasyonunuz olsa da).

11
Bir örnekte kısalık anlıyorum, ama neden sadece örnek yöntemi yutmak ve anlamsız bir değer döndürmek yerine IOException atmak değil?
sarkık

4
'dönüş null' dan 'IOException atmak' için değiştirme özgürlüğünü
aldım

3
Kaynaklarla deneme gerekli değildir, çünkü ByteArrayOutputStream # close () hiçbir şey yapmaz. (ByteArrayOutputStream # flush () gerekli değildir ve hiçbir şey yapmaz.)
Luke Hutchison

25

Güvenli çözüm (closedoğru akış akışı ile):

  • Java 9+ sürümü:

    final byte[] bytes;
    try (inputStream) {
        bytes = inputStream.readAllBytes();
    }
  • Java 8 sürümü:

    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 sürümü (Java 9+ erişilebilir olmadığında):

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

    İç içe geçmekten kaçınmak useiçin buraya bakın .


Hem tampon hem de bayt dizisine sahip olduğunuz için, bir noktada kullanılan belleğin iki katına sahip olacağınız anlamına gelmiyor mu? Baytları doğrudan çıkış bayt dizisine göndermenin bir yolu yok mu?
android geliştirici

@Android geliştiricisi; Üzgünüm. Cevabı bilmiyorum! Ama ben öyle düşünmüyorum. Bu şekilde (tampon kullanarak) optimize edilmiş bir yol olduğunu düşünüyorum.
Mir-Ismaili

Kontrol ettim ve öyle, ama boyutu bilmediğinizde seçebileceğiniz tek çözüm gibi görünüyor. Boyutu zaten biliyorsanız, verilen boyutla doğrudan bayt dizisini oluşturabilir ve doldurabilirsiniz. Bu nedenle, bayt boyutunun bir parametresini alacak bir işlev kullanırsınız ve geçerliyse, başka bir büyük nesne oluşturmadan doğrudan bayt dizisini oluşturmak ve doldurmak için kullanın.
android geliştirici

@Android geliştiricisi; Bilgi için teşekkürler. Onları tanımıyordum.
Mir-Ismaili

19

Görüntüye gerçekten ihtiyacınız var byte[]mı? Tam olarak ne bekliyorsunuz byte[]- görüntü dosyasının içinde bulunduğu formatta kodlanmış bir görüntü dosyasının veya RGB piksel değerlerinin tam içeriği?

Buradaki diğer yanıtlar, bir dosyanın nasıl okunacağını gösterir byte[]. Dosyanız byte[]içeriğin tam içeriğini içerecektir ve görüntü verileriyle herhangi bir şey yapmak için bunu çözmeniz gerekir.

Java'nın görüntüleri okumak (ve yazmak) için standart API'si, pakette bulabileceğiniz ImageIO API'sıdır javax.imageio. Bir görüntüden yalnızca tek bir kod satırı ile bir görüntüde okuyabilirsiniz:

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

Bu size a verir BufferedImage, a değil byte[]. Görüntü verilerine getRaster()ulaşmak için BufferedImage. Bu size Rasterpiksel verilerine erişmek için yöntemleri olan bir nesne verecektir (birkaç getPixel()/ getPixels()yöntemi vardır).

API belgelerini arama için javax.imageio.ImageIO, java.awt.image.BufferedImage, java.awt.image.Rastervb

ImageIO varsayılan olarak bir dizi görüntü formatını destekler: JPEG, PNG, BMP, WBMP ve GIF. Daha fazla biçim için destek eklemek mümkündür (ImageIO servis sağlayıcı arayüzünü uygulayan bir eklentiye ihtiyacınız vardır).

Ayrıca aşağıdaki eğiticiye bakın: Görüntülerle Çalışma


16

Birisi hala bağımlılığı olmayan bir çözüm arıyor ve bir dosyanız varsa .

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

Diyelim ki, bayt dizisi yığın için OOM'ye neden olabilecek çok büyükse? Baytları saklamak için JNI'yi kullanacak benzer bir çözüm var mı ve daha sonra orada saklanan verilerden (bir çeşit geçici önbellek) inputStream'i kullanabilir miyiz?
android geliştirici

14

Apache ortak kitaplığını kullanmak istemiyorsanız, bu pasaj sun.misc.IOUtils sınıfından alınır. ByteBuffers kullanan ortak uygulamanın neredeyse iki katıdır:

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

Bu biraz garip bir çözüm, uzunluk dizinin uzunluğunda bir üst sınır. Uzunluğu biliyorsanız, tek ihtiyacınız olan: byte [] output = new byte [length]; is.read (çıkış); (ama cevabımı gör)
Luke Hutchison

@ luke-hutchison dediğim gibi, bu sun.misc.IOUtils'in çözümü. En yaygın durumlarda, bir InputStream öğesinin boyutunu bilmezsiniz, bu nedenle (length == -1) length = Integer.MAX_VALUE; geçerlidir. Bu çözüm, verilen uzunluk InputStream'in uzunluğundan daha büyük olsa bile çalışır.
Kristian Kraljic

@LukeHutchison Uzunluğunu biliyorsanız birkaç satırla başa çıkabilirsiniz. Her cevaba bakarsanız, herkes uzunluğun bilinmediğinden şikayet ediyor. Son olarak standart bir yanıt Java 7 Android ile kullanılabilir ve herhangi bir harici kütüphane gerektirmez.
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: Tampondan tamamen kaçınabilirsiniz.

Kod http://www.exampledepot.com/egs/java.io/File2ByteArray.html adresinden kopyalandı (Evet, çok ayrıntılı, ancak diğer çözüm olarak belleğin yarısının boyutuna ihtiyacı var.)

// 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
Ön boyutu bilmek bağlıdır.
stolsvik

2
Tabii ki, ama onlar boyutunu bilmek gerekir: "Ben bir görüntü okumak istiyorum"
pihentagy

1
boyutu biliyorsanız, java sizin için kodu sağlar. "DataInputStream" için cevabımı veya google'ı görüyorum ve readFully yöntemi.
dermoritz

Sen eklemek gerekir is.close()eğer offset < bytes.lengthyoksa InputStreamo istisnası atılır eğer kapalı olmayacak.
Jared Rummler

3
O zaman daha iyi, kaynakları denemelisiniz
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();

Ancak, genellikle işletim sistemi zaten bunun için yeterli tamponlar daha küçük dosyalar için büyük bir endişe olmayabilir. Sabit disk kafası her baytı ayrı ayrı okuyacak gibi değil (sabit disk, üzerinde manyetik kodlanmış bilgiler bulunan bir cam plaka, veri kaydetmek için kullandığımız tuhaf simge gibi: P).
Maarten Bodewes

6
@Maarten Bodewes: Çoğu cihazın bir tür blok aktarımı vardır, bu nedenle her read () gerçek bir cihaz erişimine neden olmaz, ancak bayt başına bir OS çağrısı olması performansı öldürmek için zaten yeterlidir. Sarma iken InputStreambir de BufferedInputStreamOS-aramaları azaltmak ve önemli ölçüde performans dezavantajları telafi edeceğini kodundan önce, bu kod yine başka bir tampon gereksiz manuel kopyalama işleri yapacaktır.
Holger

4

Java 9 nihayet size güzel bir yöntem verecektir:

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

4
Bu ve InputStram.readAllBytes()tek astar arasındaki fark nedir ?
Slava Semushin

2

Çok geç olduğunu biliyorum ama burada daha okunabilir olan daha temiz bir çözüm olduğunu düşünüyorum ...

/**
 * 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
Kaynaklarla deneme özelliğini kullanmalısınız.
Victor Stafusa

Hata durumunda sonunda toparlanmanızın nihayet bir blokta yapılması gerekir, aksi takdirde bu bellek sızıntısına neden olabilir.
MGDavies

2

Java 8 yolu ( BufferedReader ve Adam Bien sayesinde )

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

Not Bu çözeltiye silme bezlerinin bir satır başı ( '\ R') ve uygunsuz olabilir.


4
Bunun için String. OP istiyor byte[].
FrozenFire

Bu sadece \rbir sorun değil. Bu yöntem, baytları karakterlere ve tekrar geri dönüştürür (InputStreamReader için varsayılan karakter kümesini kullanarak). Varsayılan karakter kodlamasında geçerli olmayan tüm baytlar (diyelim ki Linux'ta UTF-8 için -1), baytların sayısını bile değiştirebilir.
seanf

Bu iyi bir cevap gibi görünüyor, ancak metin odaklı. Alıcı dikkat.
Wheezil

1

Çöp verilerini yazmak için bir düzeltme ile @ numan'ın cevabını düzenlemeye çalıştım, ancak düzenleme reddedildi. Bu kısa kod parçası parlak bir şey olmasa da, daha iyi bir cevap göremiyorum. Benim için en anlamlı olan şey:

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 öğesinin kapatılması gerekmez. okunabilirlik için atlanmıştır


1

InputStream.available()Belgelere bakın :

Kapsayıcı boyutlandırmak için bu yöntemi kullanmamanız gerektiğini ve kapsayıcıyı yeniden boyutlandırmaya gerek kalmadan akışın tamamını okuyabileceğinizi varsaymanız özellikle önemlidir. Bu tür arayanlar muhtemelen okudukları her şeyi bir ByteArrayOutputStream öğesine yazmalı ve bunu bir bayt dizisine dönüştürmelidir. Alternatif olarak, bir dosyadan okuyorsanız, File.length dosyanın geçerli uzunluğunu döndürür (dosyanın uzunluğunun değişemeyeceğini varsayarsak, bir dosyayı okumak doğal olarak açıktır).


1

Herhangi bir nedenden ötürü masanın dışındaysa bir DataInputStream içine sarın, sadece -1 veya istediğiniz tüm bloğu verene kadar çekiçle okumak için kullanın.

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

S3 nesnesini ByteArray'e dönüştürürken birkaç AWS işlemi için biraz gecikme görüyoruz.

Not: S3 Nesnesi PDF belgesidir (maksimum boyut 3 mb'dir).

S3 nesnesini ByteArray'e dönüştürmek için # 1 seçeneğini (org.apache.commons.io.IOUtils) kullanıyoruz. S3'ün S3 nesnesini ByteArray'e dönüştürmek için inbuild IOUtils yöntemini sağladığını fark ettik, gecikmeyi önlemek için S3 nesnesini ByteArray'e dönüştürmenin en iyi yolunun ne olduğunu onaylamanızı rica ediyoruz.

Seçenek 1:

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

Seçenek 2:

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

Ayrıca s3 nesnesini bytearray'a dönüştürmek için daha iyi bir yolumuz varsa bize bildirin


0

Diğer durum, sunucuya istek gönderdikten ve yanıtı bekledikten sonra akış yoluyla doğru bayt dizisini almak için.

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

ByteArrayOutputStream kullanıyorsanız ekstra bir kopya yapıyorsunuz. Akışın okumaya başlamadan önce uzunluğunu biliyorsanız (örneğin, InputStream aslında bir FileInputStream'dir ve dosyada file.length () yöntemini çağırabilirsiniz veya InputStream, InputStream adlı bir zipfile girdisidir ve zipEntry öğesini çağırabilirsiniz. length ()) kullanırsanız, doğrudan byte [] dizisine yazmak çok daha iyidir - belleğin yarısını kullanır ve zaman kazandırır.

// 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 akışı okunurken sen olma olasılığını işlemek gerekiyorsa, ancak dosya alırsa dosyalarla fırsatlar, kesilmiş alma yukarıdaki son satırı artık akışı okunurken, bayt içinde içindekiler [] dizi uzar olmayacak yeni dosya içeriğini dahil etmek için dizi basitçe eski inputStreamLength uzunluk girişine kısaltılacaktır .


0

Bunu kullanıyorum.

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
Bu cevabın mevcut sorunu
çözmede OP'ye

0

Bu benim kopyala-yapıştır versiyonum:

@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
Bu kod snippet'i soruyu çözebilir, ancak bir açıklama da dahil olmak üzere , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
Ferrybig

0

Java 7 ve üstü:

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

20
sun.misc.IOUtils"Java 7" değildir. Diğer JRE uygulamalarında bulunmayan ve sonraki sürümlerden herhangi birinde uyarı olmadan kaybolabilen tescilli, uygulamaya özel bir sınıftır.
Holger


0

Veri baytlarını mümkün olduğunca kopyalamaktan kaçınmaya çalışan optimize edilmiş bir sürüm:

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

Kotlin'deki çözüm (elbette Java'da da çalışacaktır), her iki durumu da bildiğinizde veya bilmediğinizde:

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

Boyutu biliyorsanız, diğer çözümlere kıyasla kullanılan hafızanın iki katından tasarruf etmenizi sağlar (kısa bir süre içinde, ancak yine de yararlı olabilir). Bunun nedeni, tüm akışı sonuna kadar okumanız ve daha sonra bunu bir bayt dizisine (yalnızca bir diziye dönüştürdüğünüz ArrayList'e benzer) dönüştürmeniz gerektiğidir.

Örneğin, Android'de iseniz ve işlemek için bazı Uri'niz varsa, bunu kullanarak boyutu almaya çalışabilirsiniz:

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

Patronları kapatmak ve yıkamak klavye tıklamaları kaybıdır. Giriş akışının kapatılmasına yardımcı olma olasılığı daha yüksektir. Bir seferde bir bayt okumak verimsizdir. Numan'ın cevabına bakınız.
akostadinov
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.