Java에서 InputStream을 바이트 배열로 변환


답변:


1135

Apache Commons IO 를 사용 하여 이와 유사한 작업을 처리 할 수 있습니다 .

IOUtils유형은을 읽을 수있는 정적 메소드가 InputStream와를 반환을 byte[].

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

내부적으로 이것은 a를 생성 ByteArrayOutputStream하고 바이트를 출력에 복사 한 다음을 호출합니다 toByteArray(). 4KiB의 블록으로 바이트를 복사하여 큰 파일을 처리합니다.


188
4 줄의 코드를 작성하려면 타사 의존성을 가져 오는 것이 가치가 있다고 생각하십니까?
oxbow_lakes

217
요구 사항을 처리하고 큰 파일 처리를 처리하고 테스트가 잘된 라이브러리가있는 경우 반드시 직접 작성해야하는 이유는 무엇입니까? 항아리는 107KB에 불과하며 한 가지 방법이 필요하다면 다른 방법도 사용할 수 있습니다
Rich Seller

242
@oxbow_lakes :의 압도적 인 양을 고려하여 잘못 내 개발자 인생에서 본 적이이 기능의 구현은, 나는 느낌 그것의 매우 많은 가치가 바로 그것을 얻을 수있는 외부 의존성.
Joachim Sauer 2018 년

17
아파치 커먼즈 (Apache commons) FastArrayList또는 소프트 및 취약한 참조 맵을 살펴보고이 라이브러리가 어떻게 "잘 테스트"되었는지 알려주십시오. 쓰레기 더미입니다
oxbow_lakes 7

87
Apache commons-io 외에도 Google GuavaByteStreams 클래스를 확인하십시오 . InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
michaelok

446

에서 각 바이트를 읽고에 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);
}

return buffer.toByteArray();

16
새로 작성된 바이트의 크기는 어떻습니까? 왜 16384입니까? 정확한 크기를 어떻게 알 수 있습니까? 대단히 감사합니다.
Ondrej Bozek

6
16384는 배열이 워드 경계에 정렬 될 가능성을 높이기 위해 2의 거듭 제곱을 선호하는 경향이 있지만 상당히 임의의 선택입니다. pihentagy의 답변은 중간 버퍼를 사용하지 않고 올바른 크기의 배열을 할당하는 방법을 보여줍니다. 큰 파일을 다루지 않는 한 개인적으로 위의 코드를 선호합니다. 더 우아하고 읽을 바이트 수를 미리 알 수없는 InputStreams에 사용할 수 있습니다.
Adamski

@Adamski 데이터가 스트림에있을 것으로 예상되는 것보다 훨씬 큰 바이트 배열을 만들지 않고 메모리를 낭비합니까?
Paul Brewczynski

@ bluesm : 예 맞습니다. 그러나 내 예제에서 바이트 배열은 16Kb에 불과하며 오늘날의 표준에 따라 매우 작습니다. 또한이 메모리는 나중에 다시 해제됩니다.
Adamski

5
@Adamski 많은 인프라 하드웨어, 웹 서버 및 OS 계층 구성 요소가 4K 버퍼를 사용하여 데이터를 이동하므로 정확한 수의 이유이지만 4K를 초과하여 성능이 약간 향상됩니다. 일반적으로 메모리 낭비로 간주됩니다. 나는 이것이 10 년 된 지식이기 때문에 이것이 여전히 옳다고 가정합니다 !


132

바닐라 자바 DataInputStream와 그 readFully방법을 사용하십시오 (적어도 Java 1.4부터 존재합니다).

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

이 방법에는 다른 맛이 있지만이 사용 사례에는 항상 이것을 사용합니다.


45
타사 종속성 대신 표준 라이브러리를 사용하는 경우 +1 불행히도 스트림의 길이를 미리 알지 못하기 때문에 작동하지 않습니다.
Andrew Spencer

2
imgFile이란 무엇입니까? 그것은이 방법의 입력으로 가정 된의 InputStream, 수 없습니다입니다
야누스 Troelsen

4
@janus "파일"입니다. 이 방법은 파일의 길이 또는 읽을 바이트 수를 알고있는 경우에만 작동합니다.
dermoritz

5
재미있는 점이지만 읽을 스트림의 정확한 길이를 알아야합니다. 또한 클래스 DataInputStream는 스트림에서 기본 유형 (Longs, Shorts, Chars ...)을 읽는 데 사용되는 기본 클래스 이므로이 사용법을 클래스의 오용으로 볼 수 있습니다.
Olivier Faucheux

17
스트림에서 읽을 데이터의 길이를 이미 알고 있다면 이보다 좋습니다 InputStream.read.
Logan Pickup

119

google guava 를 사용하면 다음 과 같이 간단합니다.

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

8
ByteStreams님이 주석을 추가했습니다@Beta
Kid101

46

항상 그렇듯이 Spring 프레임 워크 (3.2.2 이후의 스프링 코어)에는 다음과 같은 것이 있습니다.StreamUtils.copyToByteArray()


대부분의 다른 사람들과 마찬가지로 타사 라이브러리를 너무 간단한 것으로 사용하지 않으려 고했지만 Java 9는 현재 옵션이 아닙니다 ... 행운 적으로 이미 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
예를 들자면 간결함은 오늘의 순서입니다. 또한 경우에 따라 null을 반환하면 프로덕션 환경에서는 적절한 예외 처리 및 문서화가 있지만 적절한 선택이 될 수 있습니다.

11
예제의 간결함을 이해하지만 예제 메소드가 IOException을 삼키고 의미없는 값을 반환하는 대신 IOException을 발생시키는 이유는 무엇입니까?
pendor

4
나는 '널 리턴'에서 'throw IOException'으로 자유를
옮겼습니다

3
ByteArrayOutputStream # close ()는 아무것도하지 않기 때문에 Try-with-resources는 필요하지 않습니다. (있는 ByteArrayOutputStream 번호 플러시 ()가 필요하고 너무 아무것도하지 않습니다하지 않습니다.)
누가 복음 허치슨에게

25

안전한 솔루션 (close스트림기능이올바르게 제공됨) :

  • Java 9+ 버전 :

    final byte[] bytes;
    try (inputStream) {
        bytes = inputStream.readAllBytes();
    }
  • 자바 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);
            }
        }
    }
  • Kotlin 버전 (Java 9+에 액세스 할 수없는 경우) :

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

    중첩을 피하려면 여기를use 참조 하십시오 .


그것은 버퍼와 바이트 배열을 모두 가지고 있기 때문에 어느 시점에서 사용 된 메모리가 두 배라는 것을 의미하지 않습니까? 바이트를 출력 바이트 배열로 직접 보내는 방법이 없습니까?
안드로이드 개발자

@androiddeveloper; 죄송 해요. 나는 답을 모른다! 그러나 나는 그렇게 생각하지 않습니다. 나는이 방법 (버퍼 사용)이 최적화 된 방법이라고 생각합니다.
Mir-Ismaili

나는 확인했지만 그것이 크기를 모르는 경우 선택할 수있는 유일한 솔루션 인 것 같습니다. 이미 크기를 알고 있다면 주어진 크기의 바이트 배열을 직접 작성하여 채울 수 있습니다. 따라서 바이트 크기의 매개 변수를 가져 오는 함수를 사용하고 유효한 경우 다른 큰 객체를 만들지 않고 바이트 배열을 직접 만들고 채우려면이 함수를 사용하십시오.
안드로이드 개발자

@androiddeveloper; 정보 주셔서 감사합니다. 나는 그들을 몰랐다.
Mir-Ismaili

19

당신은 정말 이미지가 필요 byte[]합니까? byte[]이미지 파일의 전체 내용, 이미지 파일의 형식 또는 RGB 픽셀 값으로 인코딩 된 정확한 내용은 무엇입니까?

다른 답변은 파일을로 읽는 방법을 보여줍니다 byte[]. 사용자는 byte[]파일의 정확한 내용을 포함, 당신은 이미지 데이터와 아무것도 할 것을 디코딩에 필요한 것입니다.

이미지 읽기 및 쓰기를위한 Java의 표준 API는 패키지에서 찾을 수있는 ImageIO API javax.imageio입니다. 단 한 줄의 코드로 파일에서 이미지를 읽을 수 있습니다.

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

이것은 당신에게 a 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 서비스 제공자 인터페이스를 구현하는 플러그인이 필요함).

다음 자습서를 참조하십시오. 이미지 작업


16

경우에 누군가가 여전히 의존성이없는 솔루션을 찾고 있고 파일이있는 경우 .

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

바이트 배열이 너무 커서 힙에 OOM이 발생할 수 있다면 어떻게해야합니까? JNI를 사용하여 바이트를 저장하는 비슷한 솔루션이 있으며 나중에 저장된 데이터 (일시적 캐시 캐시)에서 inputStream을 사용할 수 있습니까?
안드로이드 개발자

14

Apache commons-io 라이브러리를 사용하지 않으려면이 스 니펫은 sun.misc.IOUtils 클래스에서 가져옵니다. ByteBuffer를 사용하는 일반적인 구현보다 거의 두 배 빠릅니다.

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

이것은 약간 이상한 해결책이며 길이 는 배열 길이의 상한입니다. 길이를 알고 있으면 필요한 것은 다음과 같습니다. byte [] output = new byte [length]; is.read (출력); (그러나 내 답변 참조)
Luke Hutchison

내가 말했듯이 @ luke-hutchison은 이것이 sun.misc.IOUtils의 솔루션입니다. 가장 일반적인 경우에는 입력 스트림의 크기를 미리 알 수 없으므로 (length == -1) length = Integer.MAX_VALUE; 적용됩니다. 주어진 길이가 InputStream의 길이보다 길더라도이 솔루션은 작동합니다.
Kristian Kraljic

@LukeHutchison 길이를 아는 경우 몇 줄로 처리 할 수 ​​있습니다. 각 답변을 보면 모든 사람이 길이를 알 수 없다고 불평합니다. 마지막으로 표준이며 정답은 Java 7 Android와 함께 사용할 수 있으며 외부 라이브러리가 필요하지 않습니다.
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 : 버퍼를 완전히 피할 수 있습니다.

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

5
크기를 미리 알고 있어야합니다.
stolsvik

2
물론, 그러나 크기를 알아야합니다. "이미지를 읽고 싶습니다"
pihentagy

1
크기를 알고 있다면 java가 코드를 제공합니다. "DataInputStream"에 대한 내 답변이나 Google을 참조하십시오.
dermoritz

당신은 추가해야 is.close()하는 경우 offset < bytes.length또는는 InputStream그 예외가 발생하면 닫히지 않습니다.
Jared Rummler

3
그렇다면 더 나은 리소스를 사용해보십시오
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();

그러나 일반적으로 OS는 이미 충분히 버퍼링하므로 작은 파일에는 큰 걱정이되지 않습니다. 하드 디스크 헤드가 각 바이트를 개별적으로 읽는 것과는 다릅니다 (하드 디스크는 자기 코딩 정보가있는 회전 유리판입니다. 데이터를 저장하는 데 사용되는 이상한 아이콘과 비슷합니다 : P).
Maarten Bodewes

6
@Maarten Bodewes : 대부분의 장치에는 일종의 블록 전송이 있으므로 모든 read ()가 실제 장치 액세스를 유발하지는 않지만 바이트 당 OS 호출이 이미 성능을 저하시키기에 충분합니다. 포장하는 동안 InputStreamA의를 BufferedInputStream운영 체제-통화를 줄이고 크게 성능의 단점을 완화시킬 그 코드 전에, 그 코드는 또 다른 하나의 버퍼에서 불필요한 수동 복사 작업을 할 것입니다.
Holger

4

Java 9는 마침내 멋진 방법을 제공합니다.

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

4
이것과 InputStram.readAllBytes()그 차이점은 무엇입니까 ?
Slava Semushin

2

너무 늦었다는 것을 알고 있지만 더 읽기 쉬운 솔루션이라고 생각합니다 ...

/**
 * 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
try-with-resources를 사용해야합니다.
Victor Stafusa

오류가 발생한 경우 최종적으로 정리를 최종 블록에서 수행해야합니다. 그렇지 않으면 메모리 누수가 발생할 수 있습니다.
MGDavies

2

Java 8 방식 ( BufferedReaderAdam 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>);
    }
}

참고 용액 물티슈 것을 캐리지 리턴 ( '\ R')를 부적절 할 수있다.


4
을위한 것 String입니다. OP가 요청합니다 byte[].
FrozenFire

그냥 아니에요 \r그건 문제가 될 수 있습니다. 이 메소드는 바이트를 문자로 변환 한 후 다시 변환합니다 (InputStreamReader의 기본 문자 세트 사용). 기본 문자 인코딩에서 유효하지 않은 바이트 (예 : Linux에서 UTF-8의 경우 -1)는 손상되어 바이트 수를 변경하기도합니다.
seanf

이것은 좋은 대답이지만 텍스트 지향적 인 것 같습니다. 구매자는 조심하십시오.
Wheezil

1

가비지 데이터를 쓰는 수정으로 @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();

btw ByteArrayOutputStream을 닫을 필요는 없습니다. 가독성을 위해 생략 된 try / finally 구성


1

InputStream.available()설명서를 참조하십시오 .

컨테이너의 크기를 조정하기 위해이 방법을 사용해서는 안되며 컨테이너의 크기를 조정할 필요없이 스트림 전체를 읽을 수 있다고 가정하는 것이 특히 중요합니다. 그러한 호출자는 아마도 그들이 읽은 모든 것을 ByteArrayOutputStream에 쓰고 바이트 배열로 변환해야 할 것입니다. 또는 파일에서 읽는 경우 File.length는 파일의 현재 길이를 반환합니다 (파일의 길이를 변경할 수 없다고 가정 할 경우 파일을 읽는 것이 본질적으로 정확하지 않음).


1

어떤 이유로 테이블에서 꺼져 있으면 DataInputStream으로 감싸십시오. 요청에 -1 또는 전체 블록이 나올 때까지 read를 사용하여 망치십시오.

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 객체를 ByteArray로 변환하는 동안 AWS 트랜잭션이 약간 지연 될 수 있습니다.

참고 : S3 Object는 PDF 문서입니다 (최대 크기는 3MB).

S3 객체를 ByteArray로 변환하기 위해 옵션 # 1 (org.apache.commons.io.IOUtils)을 사용하고 있습니다. 우리는 S3가 S3 객체를 ByteArray로 변환하기위한 inbuild IOUtils 메소드를 제공하는 것을 보았습니다. 지연을 피하기 위해 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 객체를 바이트 배열로 변환하는 다른 더 좋은 방법이 있는지 알려주십시오.


0

다른 경우는 서버에 요청을 보내고 응답을 기다린 후 스트림을 통해 올바른 바이트 배열을 얻는 것입니다.

/**
         * 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을 사용하는 경우 추가 사본을 작성하고 있습니다. 스트림을 읽기 전에 스트림 길이를 알고있는 경우 (예 : InputStream은 실제로 FileInputStream이고 파일에서 file.length ()를 호출하거나 InputStream이 zip 파일 항목 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);

위의 마지막 줄은 스트림을 읽는 동안 파일이 잘리는 것을 처리합니다.이 가능성을 처리해야하지만 스트림을 읽는 동안 파일이 길어 지면 byte [] 배열의 내용이 길어지지 않습니다 새 파일 내용을 포함하기 위해 배열은 단순히 이전 길이 inputStreamLength 로 잘립니다 .


0

나는 이것을 사용합니다.

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
이 답변이 현재 문제를 해결하는 데있어 OP가 어떻게 도움이되는지에 대한 답변이 포함 된 설명을 추가하십시오
ρяσѕρєя K

0

이것은 내 복사 붙여 넣기 버전입니다.

@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
이 코드 스 니펫은 문제를 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자들에게 질문에 대한 답변을 제공하므로 해당 사람들이 코드 제안의 이유를 모를 수도 있습니다.
Ferrybig

0

Java 7 이상 :

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

20
sun.misc.IOUtils"Java 7"이 아닙니다. 다른 JRE 구현에는 없을 수 있으며 다음 릴리스 중 하나에서 경고없이 사라질 수있는 독점적 인 구현 특정 클래스입니다.
Holger

0

당신은 Cactoos 를 시도 할 수 있습니다 :

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

0

다음은 가능한 한 많이 데이터 바이트를 복사하지 않도록하는 최적화 된 버전입니다.

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의 솔루션 (물론 Java에서도 작동 함)에는 크기를 알고 있는지 여부에 대한 두 가지 경우가 모두 포함됩니다.

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

크기를 알면 다른 솔루션에 비해 두 배의 메모리를 사용하는 시간을 절약 할 수 있습니다 (짧은 시간이지만 여전히 유용 할 수 있음). 전체 스트림을 끝까지 읽은 다음 바이트 배열 (배열 만 변환하는 ArrayList와 유사)로 변환해야하기 때문입니다.

예를 들어 Android를 사용하는 경우 처리 할 Uri가있는 경우 다음을 사용하여 크기를 얻으려고 시도 할 수 있습니다.

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

보스 닫기 및 플러시는 키보드 클릭으로 인한 낭비입니다. 입력 스트림을 닫는 것이 더 도움이됩니다. 한 번에 1 바이트를 읽는 것은 비효율적입니다. numan의 답변을 참조하십시오.
akostadinov
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.