Converter InputStream em matriz de bytes em Java


Respostas:


1136

Você pode usar o Apache Commons IO para lidar com essa e outras tarefas semelhantes.

O IOUtilstipo possui um método estático para ler InputStreame retornar a byte[].

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

Internamente, isso cria ae ByteArrayOutputStreamcopia os bytes para a saída e depois chama toByteArray(). Ele lida com arquivos grandes, copiando os bytes em blocos de 4KiB.


188
Por falta de escrever 4 linhas de código, você acha que vale a pena importar uma dependência de terceiros?
— Oxbow_lakes 12/08/09

217
Se existe uma biblioteca que lida com o requisito, lida com o processamento de arquivos grandes e é bem testada, certamente a pergunta é por que eu mesmo a escreveria? O jar tem apenas 107 KB e, se você precisar de um método, provavelmente usará outros também.
— Rich Seller

242
@oxbow_lakes: considerando a quantidade impressionante de errado implementações deste recurso que já vi em minha vida desenvolvedor, eu sinto que sim , é muito muito valor a dependência externa de acertar.
— Joachim Sauer

17
Por que não dar uma olhada no Apache commons, como em FastArrayListseus mapas de referência suaves e fracos, e voltar para me dizer como esta biblioteca é "bem testada". É uma pilha de lixo
— oxbow_lakes

87
Além do Apache commons-io, confira a classe ByteStreams no Google Guava . InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
— michaelok

446

Você precisa ler cada byte do seu InputStreame gravá-lo em a ByteArrayOutputStream.

Você pode recuperar a matriz de bytes subjacente chamando 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();

17
E o tamanho do byte recém-criado []. Por que é 16384? Como posso determinar o tamanho exato exato? Muito obrigado.
— Ondrej Bozek

6
16384 é uma escolha bastante arbitrária, embora eu tenha tendência a favorecer potências de 2 para aumentar a chance da matriz se alinhar com os limites das palavras. A resposta da pihentagy mostra como você pode evitar o uso de um buffer intermediário, mas alocar uma matriz do tamanho correto. A menos que você esteja lidando com arquivos grandes, eu pessoalmente prefiro o código acima, que é mais elegante e pode ser usado para InputStreams em que o número de bytes a serem lidos não é conhecido antecipadamente.
— Adamski

@Adamski A criação de uma matriz de bytes não é muito maior do que você espera que os dados estejam no fluxo, desperdiça a memória?
— Paul Brewczynski

@ bluesm: Sim, está correto. No entanto, no meu exemplo, a matriz de bytes é de apenas 16 KB e é minúscula para os padrões atuais. Além disso, é claro que essa memória será liberada novamente posteriormente.
— Adamski

5
@Adamski Um monte de hardware de infraestrutura, servidores da web e componentes da camada do sistema operacional estão usando buffers de 4K para mover dados, então esse é o motivo do número exato, mas o ponto principal é que você obtém tão pouco aumento de desempenho ao passar por 4K que geralmente é considerado um desperdício de memória. Eu estou supondo que isso ainda é verdade, porque é o conhecimento que tenho há uma década!


132

Use baunilha Java DataInputStreame seu readFullymétodo (existe desde pelo menos Java 1.4):

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

Existem outros tipos desse método, mas eu uso isso o tempo todo para este caso de uso.


45
+1 por usar as bibliotecas padrão em vez de uma dependência de terceiros. Infelizmente, isso não funciona para mim porque não sei a duração do fluxo antecipadamente.
— Andrew Spencer

2
o que é imgFile? Não pode ser um InputStream, que deveria ser a entrada desse método
— Janus Troelsen

4
@janus é um "arquivo". dessa forma, só funciona se você souber o comprimento do arquivo ou a contagem de bytes a serem lidos.
— Dermoritz

5
Interessante, mas você deve saber o comprimento exato do (parte do) fluxo para ler. Além disso, a classe DataInputStreamé usada principalmente para ler tipos primários (Longs, Shorts, Chars ...) de um fluxo, para que possamos ver esse uso como um uso indevido da classe.
— Olivier Faucheux

17
Se você já sabe o tamanho dos dados a serem lidos do fluxo, isso não é melhor que InputStream.read.
— Logan Pickup

119

Se você usar google goiaba , será tão simples quanto:

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

8
ByteStreamsé anotado com@Beta
— Kid101

46

Como sempre, também o framework Spring (core desde 3.2.2) tem algo para você:StreamUtils.copyToByteArray()


Como a maioria dos outros, eu queria evitar o uso de uma biblioteca de terceiros para algo tão simples, mas o Java 9 não é uma opção no momento ... felizmente, eu já estava usando o 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();
}

2
É um exemplo e, como tal, a brevidade está na ordem do dia. Também retornar nulo aqui seria a escolha adequada em alguns casos (embora em um ambiente de produção você também tenha manipulação e documentação de exceção).

11
Entendo a brevidade em um exemplo, mas por que não fazer o método de exemplo lançar IOException em vez de engoli-lo e retornar um valor sem sentido?
— Pendor

4
Tomei a liberdade de mudar de 'null retorno' para 'jogar IOException'
— kritzikratzi

3
A tentativa com recursos não é necessária aqui, porque ByteArrayOutputStream # close () não faz nada. (ByteArrayOutputStream # flush () não é necessário e também não faz nada.)
— Luke Hutchison

25

Solução segura (com capacidade declosefluxos corretamente):

  • Versão Java 9+:

    final byte[] bytes;
    try (inputStream) {
        bytes = inputStream.readAllBytes();
    }
  • Versão 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);
            }
        }
    }
  • Versão Kotlin (quando o Java 9+ não está acessível):

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

    Para evitar aninhados, useveja aqui .


Isso não significa que, em algum momento, você teria o dobro da memória usada, porque possui o buffer e a matriz de bytes? Não existe uma maneira de enviar os bytes diretamente para a matriz de bytes de saída?
— desenvolvedor android

@androiddeveloper; Eu sinto Muito. Eu não sei a resposta! Mas acho que não. Eu acho que desta maneira (usando buffer) é uma maneira otimizada.
— Mir-Ismaili

Eu verifiquei e sim, mas parece que é a única solução que você pode escolher quando não sabe o tamanho. Se você já conhece o tamanho, pode criar diretamente a matriz de bytes com o tamanho especificado e preenchê-lo. Portanto, você usa uma função que obterá um parâmetro do tamanho de bytes e, se for válido, use-a para criar e preencher diretamente a matriz de bytes, sem criar nenhum outro objeto grande.
— desenvolvedor android

@androiddeveloper; Obrigado pela sua informação. Eu não os conhecia.
— Mir-Ismaili

19

Você realmente precisa da imagem como um byte[]? O que exatamente você espera nobyte[] - o conteúdo completo de um arquivo de imagem, codificado em qualquer formato em que esteja o arquivo de imagem ou em valores de pixel RGB?

Outras respostas aqui mostram como ler um arquivo em um arquivo byte[]. Você byte[]conterá o conteúdo exato do arquivo e você precisará decodificá-lo para fazer qualquer coisa com os dados da imagem.

A API padrão do Java para leitura (e gravação) de imagens é a API ImageIO, que você pode encontrar no pacote javax.imageio. Você pode ler uma imagem de um arquivo com apenas uma única linha de código:

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

Isso lhe dará um BufferedImage, não um byte[]. Para acessar getRaster()os dados da imagem, você pode acessar o BufferedImage. Isso fornecerá um Rasterobjeto, que possui métodos para acessar os dados de pixel (possui vários getPixel()/ getPixels()métodos).

Pesquisar a documentação da API para javax.imageio.ImageIO, java.awt.image.BufferedImage, java.awt.image.Rasteretc.

O ImageIO suporta vários formatos de imagem por padrão: JPEG, PNG, BMP, WBMP e GIF. É possível adicionar suporte para mais formatos (você precisaria de um plug-in que implemente a interface do provedor de serviços ImageIO).

Consulte também o seguinte tutorial: Trabalhando com imagens


16

No caso de alguém ainda estar procurando uma solução sem dependência e se você tiver um arquivo .

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

Digamos, e se a matriz de bytes for muito grande, o que poderia causar OOM para o heap? Existe uma solução semelhante que usará o JNI para armazenar os bytes e, mais tarde, poderemos usar o inputStream a partir dos dados armazenados lá (tipo de cache temporário)?
— desenvolvedor android

14

Se você não deseja usar a biblioteca do Apache commons-io, esse trecho é retirado da classe sun.misc.IOUtils. É quase duas vezes mais rápido que a implementação comum usando 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;
}

Essa é uma solução um pouco estranha, o comprimento é um limite superior do comprimento da matriz. Se você conhece o tamanho, tudo o que precisa é: byte [] output = new byte [length]; is.read (saída); (mas veja minha resposta)
— Luke Hutchison

@ luke-hutchison como eu disse, esta é a solução do sun.misc.IOUtils. Nos casos mais comuns, você não sabe o tamanho de um InputStream antecipadamente, portanto, se (length == -1) length = Integer.MAX_VALUE; aplica-se. Essa solução funciona, mesmo se o comprimento especificado for maior que o comprimento do InputStream.
— Kristian Kraljic 31/07/2015

@LukeHutchison Se você souber o comprimento, poderá lidar com ele com algumas linhas. Se você olhar para cada resposta, todo mundo está reclamando que o comprimento não é conhecido. Finalmente, uma resposta que é padrão, pode ser usada com o Java 7 Android e não requer nenhuma biblioteca externa.
— Csaba Toth 27/02

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: Você pode evitar o buffer inteiramente.

Código copiado de http://www.exampledepot.com/egs/java.io/File2ByteArray.html (Sim, é muito detalhado, mas precisa da metade do tamanho da memória que a outra solução.)

// 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
Depende do tamanho do conhecimento antecipadamente.
— amigos estão dizendo sobre stolsvik

2
Claro, mas eles devem saber o tamanho: "Eu quero ler uma imagem"
— pihentagy

1
se você souber o tamanho, o java fornecerá o código para você. veja minha resposta ou google para "DataInputStream" e é método readFully.
— Dermoritz 28/05

Você deve adicionar is.close()se offset < bytes.lengthou InputStreamnão será fechado se essa exceção for lançada.
— Jared Rummler

3
Então é melhor, você deve usar try-with-recursos
— 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();

No entanto, geralmente o sistema operacional já possui buffers suficientes para que isso não seja uma grande preocupação para arquivos menores. Não é como se a cabeça do disco rígido lesse cada byte separadamente (um disco rígido é uma placa de vidro giratória com informações magnéticas, um pouco como o ícone estranho que usamos para salvar dados: P).
— Maarten Bodewes

6
@Maarten Bodewes: a maioria dos dispositivos possui um tipo de transferência de bloco; portanto, nem toda leitura () causa um acesso real ao dispositivo, mas ter uma chamada do SO por byte já é suficiente para diminuir o desempenho. Enquanto terminava o InputStreamem um BufferedInputStreamantes que o código reduziria os-chamadas e mitigar os inconvenientes de desempenho significativamente, que o código ainda vai fazer o trabalho de cópia manual desnecessária de um tampão para outro.
— Holger

4

O Java 9 finalmente fornecerá um bom método:

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

4
Qual é a diferença entre isso e InputStram.readAllBytes()aquilo é one-liner?
— Slava Semushin

2

Sei que é tarde demais, mas aqui acho que é uma solução mais limpa, mais legível ...

/**
 * 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
Você deve usar try-with-resources.
— Victor Stafusa

Sua organização no final precisa ser feita em um bloco finalmente em caso de erros, caso contrário, isso pode causar um vazamento de memória.
— MGDavies

2

Modo Java 8 (graças a BufferedReader e 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>);
    }
}

Observe que esta solução limpa o retorno de carro ('\ r') e pode ser inapropriada.


4
Isso é para String. OP está pedindo byte[].
— FrozenFire

Não é apenas \risso que poderia ser um problema. Este método converte os bytes em caracteres e vice-versa (usando o conjunto de caracteres padrão para InputStreamReader). Quaisquer bytes que não sejam válidos na codificação de caracteres padrão (por exemplo, -1 para UTF-8 no Linux) serão corrompidos, possivelmente alterando o número de bytes.
— seanf

Parece que esta é uma boa resposta, mas orientada para o texto. Comprador, cuidado.
— Wheezil

1

Tentei editar a resposta de @ numan com uma correção para gravar dados de lixo, mas a edição foi rejeitada. Embora esse pequeno pedaço de código não seja nada brilhante, não vejo outra resposta melhor. Aqui está o que faz mais sentido para mim:

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 não precisa ser fechado. construções try / finalmente omitidas para facilitar a leitura


1

Veja a InputStream.available()documentação:

É particularmente importante perceber que você não deve usar esse método para dimensionar um contêiner e assumir que é possível ler a totalidade do fluxo sem precisar redimensionar o contêiner. Esses chamadores provavelmente devem escrever tudo o que lêem em um ByteArrayOutputStream e convertê-lo em uma matriz de bytes. Como alternativa, se você estiver lendo um arquivo, File.length retornará o tamanho atual do arquivo (embora suponha que o tamanho do arquivo não possa ser alterado pode estar incorreto, a leitura de um arquivo é inerentemente atrevida).


1

Embrulhe-o em um DataInputStream, se isso estiver fora da mesa, por algum motivo, use read para martelá-lo até obter um -1 ou todo o bloco que você pediu.

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

Estamos vendo algum atraso para poucas transações da AWS, ao converter o objeto S3 em ByteArray.

Nota: O objeto S3 é um documento PDF (o tamanho máximo é de 3 mb).

Estamos usando a opção 1 (org.apache.commons.io.IOUtils) para converter o objeto S3 em ByteArray. Observamos que o S3 fornece o método IOUtils do inbuild para converter o objeto S3 em ByteArray, solicitamos que você confirme qual é a melhor maneira de converter o objeto S3 em ByteArray para evitar o atraso.

Opção 1:

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

Opção 2:

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

Além disso, deixe-me saber se temos outra maneira melhor de converter o objeto s3 para bytearray


0

O outro caso para obter a matriz de bytes correta via fluxo, após enviar a solicitação ao servidor e aguardar a resposta.

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

Você está fazendo uma cópia extra se usar ByteArrayOutputStream. Se você conhece o tamanho do fluxo antes de começar a lê-lo (por exemplo, o InputStream é na verdade um FileInputStream e pode chamar file.length () no arquivo, ou o InputStream é uma entrada do arquivo zip InputStream e pode chamar zipEntry. length ()), então é muito melhor escrever diretamente na matriz de bytes [] - ele usa metade da memória e economiza tempo.

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

Nota: a última linha acima lida com arquivos sendo truncados enquanto o fluxo está sendo lido, se você precisar lidar com essa possibilidade, mas se o arquivo ficar mais longo enquanto o fluxo estiver sendo lido, o conteúdo da matriz byte [] não será aumentado para incluir o novo conteúdo do arquivo, a matriz será simplesmente truncada para o comprimento antigo inputStreamLength .


0

Eu uso isso.

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
Adicione um pouco de explicação com a resposta de como essa resposta ajuda OP na fixação edição atual
— ρяσѕρєя K

0

Esta é minha versão copiar e colar:

@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
Embora esse trecho de código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código.
— precisa saber é o seguinte

0

Java 7 e posterior:

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

20
sun.misc.IOUtilsnão é "Java 7". É uma classe específica de implementação proprietária que pode não estar presente em outras implementações do JRE e pode desaparecer sem nenhum aviso em um dos próximos releases.
— Holger


0

Aqui está uma versão otimizada, que tenta evitar o máximo possível de copiar bytes de dados:

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

Solução no Kotlin (também funcionará em Java, é claro), que inclui os dois casos em que você sabe o tamanho ou não:

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

Se você souber o tamanho, poupará o dobro da memória usada em comparação com as outras soluções (em um breve momento, mas ainda pode ser útil). Isso porque você precisa ler o fluxo inteiro até o final e depois convertê-lo em uma matriz de bytes (semelhante ao ArrayList que você converte em apenas uma matriz).

Portanto, se você estiver no Android, por exemplo, e tiver um Uri para lidar, tente obter o tamanho usando este:

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

Fechar e liberar bos é um desperdício de cliques no teclado. Fechar o fluxo de entrada tem mais chances de ajudar. Ler um byte de cada vez é ineficiente. Veja a resposta de numan.
— akostadinov
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.