Конвертировать InputStream, чтобы байтовый массив в Java


Как я могу прочитать всю InputStream в массив байтов?

30 698

30 ответов:

вы можете использовать Apache Commons IO для решения этой и подобных задач.

The IOUtils тип имеет статический метод, чтобы прочитать InputStream и вернуть a byte[].

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

внутренне это создает ByteArrayOutputStream и копирует байты на выход, а затем вызывает toByteArray(). Он обрабатывает большие файлы, копируя байты в блоках 4KiB.

вам нужно прочитать каждый байт из вашего InputStream и запишите его в ByteArrayOutputStream. Затем вы можете получить базовый массив байтов, вызвав 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);
}

buffer.flush();

return buffer.toByteArray();

наконец, после двадцати лет, есть простое решение без необходимости в сторонней библиотеке, благодаря Java 9:

InputStream is;
…
byte[] array = is.readAllBytes();

обратите внимание также на методы удобства readNBytes(byte[] b, int off, int len) и transferTo(OutputStream) устранение повторяющихся потребностей.

Если вы используете google guava, это будет так :

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

используйте ваниль Java DataInputStream и readFully метод (существует, по крайней мере, с Java 1.4):

...
byte[] imgDataBa = new byte[(int)imgFile.length()];
DataInputStream dataIs = new DataInputStream(new FileInputStream(imgFile));
dataIs.readFully(imgDataBa);
...

есть несколько других разновидностей этого метода, но я использую это все время для этого случая использования.

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

Как всегда, кроме Spring framework (spring-core с 3.2.2) есть что-то для вас: StreamUtils.copyToByteArray()

вам действительно нужно изображение как byte[]? Что именно вы ожидаете в byte[] - полное содержимое файла изображения, закодированное в любом формате, в котором находится файл изображения, или значения пикселей RGB?

другие ответы здесь показать вам, как читать файл в byte[]. Ваш byte[] будет содержать точное содержимое файла, и вам нужно будет декодировать это, чтобы сделать что-нибудь с данными изображения.

стандартный API Java для чтения (и записи) изображений является ImageIO API, который вы можете найти в пакете javax.imageio. Вы можете прочитать изображение из файла только с одной строкой кода:

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

это даст вам BufferedImage, а не byte[]. Чтобы получить данные изображения, вы можете позвонить getRaster() на BufferedImage. Это даст вам Raster объект, который имеет методы для доступа к данным пикселей (он имеет несколько getPixel()/getPixels() методов).

поиск документации API для javax.imageio.ImageIO,java.awt.image.BufferedImage,java.awt.image.Raster так далее.

ImageIO поддерживает ряд форматов изображений по умолчанию: JPEG, PNG, BMP, WBMP и GIF. Можно добавить поддержку для большего количества форматов (вам понадобится плагин, который реализует интерфейс поставщика услуг ImageIO).

см. также следующий учебник:работа с изображениями

Если вы не хотите использовать библиотеку Apache commons-io, этот фрагмент взят из sun.разное.IOUtils class. Это почти в два раза быстрее, чем обычная реализация с помощью 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;
}

в случае, если кто-то все еще ищет решение без зависимости и если у вас есть файл.

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

@Adamski: вы можете полностью избежать буфера.

код скопирован из http://www.exampledepot.com/egs/java.io/File2ByteArray.html (Да, это очень многословно, но требует половину размера памяти в качестве другого решения.)

// 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;
}
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();
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 даст вам, наконец, хороший метод:

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

Я знаю, что уже слишком поздно, но здесь я думаю, что это более чистое решение, которое более читаемо...

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

Я попытался отредактировать ответ @ numan с исправлением для записи данных мусора, но редактирование было отклонено. Хотя этот короткий кусок кода не является чем-то блестящим, я не вижу другого лучшего ответа. Вот что имеет для меня наибольший смысл:

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

bytearrayoutputstream не, кстати, не должны быть закрыты. попробуйте / наконец конструкции опущены для удобочитаемости

посмотреть InputStream.available() документы:

особенно важно понимать, что вы не должны использовать это метод для определения размера контейнера и предположим, что вы можете прочитать всю информацию потока без необходимости изменять размер контейнера. Такие звонящие вероятно, следует написать все, что они читают в ByteArrayOutputStream и преобразуйте это в массив байтов. Кроме того, если Вы читаете из файла, файла.length возвращает текущую длину файла (хотя если предположить, что длина файла не может измениться, это может быть неверно, чтение файла по своей сути колоритно).

Java 7 и более поздних:

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

Java 8 способ (благодаря BufferedReader и Адам Бьен)

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

Примечание что это решение салфетки возврат каретки ('\r') и может быть неуместным.

другой случай, чтобы получить правильный массив байтов через поток, после отправки запроса на сервер и ожидания ответа.

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

вы делаете дополнительную копию, если вы используете ByteArrayOutputStream. Если вы знаете длину потока, прежде чем начать его читать (например, InputStream на самом деле является FileInputStream, и вы можете вызвать file.length () в файле или InputStream является записью zipfile InputStream, и вы можете вызвать zipEntry.length ()), то гораздо лучше писать непосредственно в массив byte [] - он использует половину памяти и экономит время.

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

N. B. последняя строка выше имеет дело с файлами получение усеченного во время чтения потока, если вам нужно обработать эту возможность, но если файл получает больше во время чтения потока содержимое массива byte[] не будет удлинено для включения нового содержимого файла, массив будет просто усечен до старой длины inputStreamLength.

Я использую это.

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

Это моя версия для копирования:

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

оберните его в DataInputStream если это по какой-то причине вне таблицы, просто используйте read, чтобы забить на него, пока он не даст вам -1 или весь блок, который вы просили.

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

вы можете попробовать Cactoos:

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

мы наблюдаем некоторую задержку для нескольких транзакций AWS, при преобразовании объекта S3 в ByteArray.

Примечание: объект S3-это PDF-документ (максимальный размер-3 МБ).

мы используем опцию #1 (org.apache.commons.io.IOUtils) для преобразования объекта S3 в ByteArray. Мы заметили, что S3 предоставляет встроенный метод IOUtils для преобразования объекта S3 в ByteArray, мы просим вас подтвердить, что это лучший способ преобразовать объект S3 в ByteArray, чтобы избежать задержка.

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

Вариант № 2:

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

также дайте мне знать, если у нас есть другой лучший способ преобразовать объект s3 в bytearray

вот оптимизированная версия, которая пытается максимально избежать копирования байтов данных:

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

Код

public static byte[] serializeObj(Object obj) throws IOException {
  ByteArrayOutputStream baOStream = new ByteArrayOutputStream();
  ObjectOutputStream objOStream = new ObjectOutputStream(baOStream);

  objOStream.writeObject(obj); 
  objOStream.flush();
  objOStream.close();
  return baOStream.toByteArray(); 
} 

или

BufferedImage img = ...
ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);
ImageIO.write(img, "jpeg", baos);
baos.flush();
byte[] result = baos.toByteArray();
baos.close();
/*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();
}

это работает для меня,

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