Converter InputStream a matriz de bytes em Java
-
13-09-2019 - |
Pergunta
Como faço para ler um InputStream
inteiro em uma matriz de bytes?
Solução
Você pode usar o Apache Commons IO para lidar com este e semelhantes tarefas.
O tipo IOUtils
tem um método estático para ler um InputStream
e retornar um byte[]
.
InputStream is;
byte[] bytes = IOUtils.toByteArray(is);
Internamente, isso cria uma ByteArrayOutputStream
e copia os bytes para a saída, em seguida, chama toByteArray()
. Ele lida com arquivos grandes, copiando os bytes em blocos de 4KiB.
Outras dicas
Você precisa ler cada byte do seu InputStream
e escrevê-lo a um ByteArrayOutputStream
. Você pode recuperar a matriz de bytes subjacentes chamando toByteArray()
; por exemplo.
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();
Finalmente, depois de vinte anos, há uma solução simples, sem a necessidade de uma biblioteca parte 3, graças a Java 9 :
InputStream is;
…
byte[] array = is.readAllBytes();
Observe também os métodos de conveniência readNBytes(byte[] b, int off, int len)
e transferTo(OutputStream)
abordar as necessidades recorrentes
DataInputStream
Use Java de baunilha e sua readFully
Method (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 alguns outros sabores de este método, mas eu uso isso o tempo todo para este caso de uso.
Se acontecer de você usar google goiaba , vai ser tão simples como:
byte[] bytes = ByteStreams.toByteArray(inputStream);
Como sempre, também Primavera quadro (primavera-core desde 3.2.2) tem algo para você: StreamUtils.copyToByteArray()
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();
}
Você realmente precisa a imagem como um byte[]
? O que exatamente você espera na byte[]
? - o conteúdo completo de um arquivo de imagem, codificada em qualquer formato do arquivo de imagem se encontra, ou valores de pixel RGB
Outras respostas aqui mostrar-lhe como ler um arquivo em um byte[]
. Seu byte[]
irá conter o conteúdo exato do arquivo, e você precisaria de decodificação que fazer alguma coisa com os dados da imagem.
API padrão do Java para leitura (e escrever) imagens é a API ImageIO, que você pode encontrar no javax.imageio
pacote. Você pode ler em uma imagem de um arquivo com apenas uma única linha de código:
BufferedImage image = ImageIO.read(new File("image.jpg"));
Isto lhe dará uma BufferedImage
, não um byte[]
. Para obter os dados de imagem, você pode chamar getRaster()
na BufferedImage
. Isto lhe dará um objeto Raster
, que tem métodos para acessar os dados de pixel (que tem vários métodos getPixel()
/ getPixels()
).
Lookup a documentação da API para javax.imageio.ImageIO
, java.awt.image.BufferedImage
, java.awt.image.Raster
etc.
ImageIO suporta um número de formatos de imagem por padrão: JPEG, PNG, BMP, WBMP e GIF. É possível adicionar suporte para mais formatos (você precisa de um plug-in que implementa a interface provedor de serviços ImageIO).
Veja também o seguinte tutorial: trabalhar com imagens
Se você não quiser usar o Apache commons-io biblioteca, 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;
}
Em caso alguém está ainda à procura de uma solução sem uma dependência e Se você tem 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);
Seguro Solução (com capacidade de close
córregos corretamente):
-
versão Java com mais de 9:
final byte[] bytes; try (inputStream) { bytes = inputStream.readAllBytes(); }
-
Java 8 versão:
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 (quando Java 9+ não é 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
use
aninhada ver aqui .
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();
@Adamski:. Você pode evitar tampão inteiramente
Código copiado de http://www.exampledepot.com/egs/java.io/File2ByteArray. html (Sim, é muito detalhado, mas precisa de metade do tamanho da memória como 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;
}
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();
Java 9 vai lhe dar, finalmente, um bom método:
InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();
Eu sei que é tarde demais, mas aqui eu acho que é solução mais limpa que é 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();
}
Java 8 vias (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>);
}
}
Nota ??strong> que esta solução toalhetes retorno de carro ( '\ r') e pode ser inadequada.
Eu tentei editar resposta da @ Numan com uma correção para escrever dados de lixo, mas edição foi rejeitada. Embora este pequeno pedaço de código não é nada brilhante que eu não consigo ver nenhuma 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 necessidade ByteArrayOutputStream não ser fechado. tente / finally construções omitidos para facilitar a leitura
Consulte a documentação InputStream.available()
:
É particularmente importante perceber que você não deve usar este método para o tamanho de um recipiente e assumir que você pode ler a totalidade do fluxo sem a necessidade de redimensionar o recipiente. tais chamadores provavelmente deve escrever tudo o que lêem a um ByteArrayOutputStream e convertê-lo em uma matriz de bytes. Alternativamente, se você estiver lendo de um arquivo, file.length retorna o comprimento atual do arquivo (Embora assumindo que o comprimento do arquivo não pode mudar pode estar incorreta, lendo um arquivo é inerentemente atrevido).
Java 7 e posterior:
import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
O outro caso para obter matriz de bytes correta via stream, após pedido de envio para o servidor e esperando 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);
Você está fazendo uma cópia extra se você usar ByteArrayOutputStream. Se você souber o comprimento do fluxo antes de começar a lê-lo (por exemplo, o InputStream é realmente um FileInputStream, e você pode chamar file.length () no arquivo, ou o InputStream é uma InputStream entrada zipfile, e você pode chamar ZipEntry. length ()), então é muito melhor para escrever diretamente para a matriz byte [] -. 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);
NB. a última linha acima lida com arquivos ficar truncado enquanto o fluxo está sendo lido, se você precisa lidar com essa possibilidade, mas se o arquivo fica mais enquanto o fluxo está sendo lido, o conteúdo do byte [ ] array não vai ser aumentado para incluir o novo conteúdo do arquivo, a matriz será simplesmente truncada para o comprimento de idade inputStreamLength .
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();
}
}
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();
}
envolvê-la em um DataInputStream se isso está fora da mesa, por algum motivo, basta usar ler a martelo sobre ele até que ele lhe dá 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;
}
Você pode tentar Cactoos :
byte[] array = new BytesOf(stream).bytes();
Estamos vendo algum atraso para poucos transação AWS, ao converter S3 objeto ByteArray.
Nota:. S3 objeto é documento PDF (tamanho máximo é de 3 mb)
Estamos usando a opção # 1 (org.apache.commons.io.IOUtils) para converter o objeto S3 para ByteArray. Temos notado S3 fornecer o método IOUtils inbuild para converter o objeto S3 para ByteArray, estamos pedir-lhe para confirmar qual é a melhor maneira de converter o objeto S3 para 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);
Também deixe-me saber se temos alguma outra maneira melhor para converter o objeto s3 para bytearray
Aqui está uma versão otimizada, que tenta evitar a cópia de bytes de dados, tanto quanto possível:
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;
}
}
/*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();
}
Isso funciona para mim,
if(inputStream != null){
ByteArrayOutputStream contentStream = readSourceContent(inputStream);
String stringContent = contentStream.toString();
byte[] byteArr = encodeString(stringContent);
}
readSourceContent ()
public static ByteArrayOutputStream readSourceContent(InputStream inputStream) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int nextChar;
try {
while ((nextChar = inputStream.read()) != -1) {
outputStream.write(nextChar);
}
outputStream.flush();
} catch (IOException e) {
throw new IOException("Exception occurred while reading content", e);
}
return outputStream;
}
encodeString ()
public static byte[] encodeString(String content) throws UnsupportedEncodingException {
byte[] bytes;
try {
bytes = content.getBytes();
} catch (UnsupportedEncodingException e) {
String msg = ENCODING + " is unsupported encoding type";
log.error(msg,e);
throw new UnsupportedEncodingException(msg, e);
}
return bytes;
}