Chuyển đổi InputStream thành mảng byte trong Java


Câu trả lời:


1135

Bạn có thể sử dụng Apache Commons IO để xử lý các tác vụ này và các tác vụ tương tự.

Các IOUtilsloại có một phương pháp tĩnh để đọc một InputStreamvà trả về một byte[].

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

Trong nội bộ, điều này tạo ra một ByteArrayOutputStreamvà sao chép các byte vào đầu ra, sau đó gọi toByteArray(). Nó xử lý các tệp lớn bằng cách sao chép các byte trong các khối 4KiB.


188
Vì muốn viết 4 dòng mã, bạn nghĩ rằng việc nhập phụ thuộc của bên thứ 3 có đáng không?
oxbow_lakes

217
Nếu có một thư viện xử lý yêu cầu và xử lý các tệp lớn và được kiểm tra tốt, chắc chắn câu hỏi là tại sao tôi lại tự viết nó? Bình chỉ có 107KB và nếu bạn cần một phương thức từ nó, bạn cũng có thể sử dụng các phương thức khác
Người bán giàu

242
@oxbow_lakes: xem xét số lượng đáng kinh ngạc sai triển khai tính năng này tôi đã nhìn thấy trong cuộc sống phát triển của tôi, tôi cảm thấy rằng rất nhiều giá trị phụ thuộc bên ngoài để làm cho nó đúng.
Joachim Sauer

17
Tại sao không đi và xem xét các công cụ Apache commons như FastArrayListhoặc Bản đồ tham khảo mềm & yếu của họ và quay lại để cho tôi biết thư viện này được "kiểm tra tốt" như thế nào. Đó là một đống rác
oxbow_lakes

87
Ngoài Apache commons-io, hãy xem lớp ByteStreams từ Google Guava . InputStream is; byte[] filedata=ByteStreams.toByteArray(is);
michaelok

446

Bạn cần đọc từng byte từ của bạn InputStreamvà viết nó vào a ByteArrayOutputStream.

Sau đó, bạn có thể truy xuất mảng byte bên dưới bằng cách gọi 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
Kích thước của byte mới được tạo []. Tại sao lại là 16384? Làm thế nào tôi có thể xác định chính xác kích thước đúng? Cảm ơn rât nhiều.
Ondrej Bozek

6
16384 là một lựa chọn khá độc đoán mặc dù tôi có xu hướng ủng hộ quyền hạn của 2 để tăng cơ hội cho mảng phù hợp với ranh giới từ. Câu trả lời của pieaveragy cho thấy cách bạn có thể tránh sử dụng bộ đệm trung gian, nhưng phân bổ một mảng có kích thước chính xác. Trừ khi bạn đang xử lý các tệp lớn, cá nhân tôi thích mã ở trên, thanh lịch hơn và có thể được sử dụng cho InputStreams nơi không biết trước số lượng byte để đọc.
Adamski

@Adamski Không tạo ra nhiều byte lớn hơn bạn mong đợi dữ liệu sẽ có trong luồng, gây lãng phí bộ nhớ?
Paul Brewczynski

@bluesm: Đúng vậy. Tuy nhiên, trong ví dụ của tôi, mảng byte chỉ 16Kb và rất nhỏ theo tiêu chuẩn ngày nay. Ngoài ra, tất nhiên bộ nhớ này sẽ được giải phóng lại sau đó.
Adamski

5
@Adamski Rất nhiều phần cứng cơ sở hạ tầng, máy chủ web và các thành phần lớp OS đang sử dụng bộ đệm 4K để di chuyển dữ liệu, vì vậy đó là lý do cho con số chính xác, nhưng điểm chính là bạn có được hiệu suất tăng ít như vậy bằng cách vượt qua 4K rằng nó thường được coi là lãng phí bộ nhớ. Tôi cho rằng điều này vẫn đúng, bởi vì tôi đã có kiến ​​thức hàng thập kỷ!


132

Sử dụng vanilla Java DataInputStreamreadFullyPhương thức của nó (tồn tại từ ít nhất Java 1.4):

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

Có một số hương vị khác của phương pháp này, nhưng tôi sử dụng tất cả thời gian cho trường hợp sử dụng này.


45
+1 để sử dụng các thư viện tiêu chuẩn thay vì phụ thuộc bên thứ 3. Thật không may, nó không hoạt động với tôi vì tôi không biết chiều dài của luồng trả trước.
Andrew Spencer

2
imgFile là gì? Nó không thể là InputStream, được cho là đầu vào của phương thức này
Janus Troelsen

4
@janus nó là một "Tập tin". cách này chỉ hoạt động nếu bạn biết độ dài của tệp hoặc số byte cần đọc.
dermoritz

5
Điều thú vị, nhưng bạn phải biết độ dài chính xác của luồng (một phần) để đọc. Hơn nữa, lớp DataInputStreamnày được sử dụng chính để đọc các loại chính (Longs, Quần short, Chars ...) từ một luồng, vì vậy chúng ta có thể thấy cách sử dụng này là lạm dụng của lớp.
Olivier Faucheux

17
Nếu bạn đã biết độ dài của dữ liệu cần đọc từ luồng, điều này không tốt hơn InputStream.read.
Pickup Logan

119

Nếu bạn tình cờ sử dụng ổi google , nó sẽ đơn giản như:

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

8
ByteStreamsđược chú thích với@Beta
Kid101

46

Như mọi khi, khung công tác Spring (core-core kể từ 3.2.2) có một cái gì đó dành cho bạn:StreamUtils.copyToByteArray()


Giống như hầu hết những người khác, tôi muốn tránh sử dụng thư viện của bên thứ 3 cho một thứ gì đó quá đơn giản, nhưng Java 9 không phải là một tùy chọn vào lúc này ... may mắn thay, tôi đã sử dụng 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
Đó là một ví dụ và như vậy, sự ngắn gọn là thứ tự trong ngày. Ngoài ra trả về null ở đây sẽ là lựa chọn thích hợp trong một số trường hợp (mặc dù trong môi trường sản xuất, bạn cũng sẽ có tài liệu và xử lý ngoại lệ phù hợp).

11
Tôi hiểu sự ngắn gọn trong một ví dụ, nhưng tại sao không làm cho phương thức ví dụ ném IOException thay vì nuốt nó và trả về một giá trị vô nghĩa?
chuyền

4
Tôi đã tự do thay đổi từ 'trở về null' thành 'ném IOException'
kritzikratzi

3
Không cần dùng thử tài nguyên ở đây, vì ByteArrayOutputStream # close () không làm gì cả. (ByteArrayOutputStream # flush () không cần thiết và cũng không có gì.)
Luke Hutchison

25

Giải pháp an toàn (với khả năng truyềnclosephát chính xác):

  • Phiên bản Java 9+:

    final byte[] bytes;
    try (inputStream) {
        bytes = inputStream.readAllBytes();
    }
  • Phiên bản 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);
            }
        }
    }
  • Phiên bản Kotlin (khi không thể truy cập 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()
        }
    }

    Để tránh lồng nhau usexem tại đây .


Điều đó không có nghĩa là tại một số điểm bạn có gấp đôi bộ nhớ được sử dụng, bởi vì bạn có cả bộ đệm và mảng byte? Có cách nào để gửi byte trực tiếp đến mảng byte đầu ra không?
nhà phát triển Android

@androiddeveloper; Tôi xin lỗi. Tôi không biết câu trả lời! Nhưng tôi không nghĩ vậy. Tôi nghĩ rằng cách này (sử dụng bộ đệm) là một cách tối ưu hóa.
Mir-Ismaili

Tôi đã kiểm tra và có, nhưng có vẻ như đó là giải pháp duy nhất bạn có thể chọn khi bạn không biết kích thước. Nếu bạn đã biết kích thước, bạn có thể trực tiếp tạo mảng byte với kích thước đã cho và điền vào nó. Vì vậy, bạn sử dụng một hàm sẽ lấy tham số có kích thước byte và nếu nó hợp lệ, hãy sử dụng nó để trực tiếp tạo và điền vào mảng byte, mà không tạo ra bất kỳ đối tượng lớn nào khác.
nhà phát triển Android

@androiddeveloper; Cảm ơn thông tin của bạn. Tôi không biết họ.
Mir-Ismaili

19

Bạn có thực sự cần hình ảnh như một byte[]? Chính xác những gì bạn mong đợi trong byte[]- nội dung đầy đủ của một tệp hình ảnh, được mã hóa ở bất kỳ định dạng nào mà tệp hình ảnh nằm trong hoặc các giá trị pixel RGB?

Các câu trả lời khác ở đây chỉ cho bạn cách đọc một tệp vào một byte[]. Của bạn byte[]sẽ chứa nội dung chính xác của tệp và bạn cần giải mã điều đó để làm bất cứ điều gì với dữ liệu hình ảnh.

API tiêu chuẩn của Java để đọc (và viết) hình ảnh là API ImageIO mà bạn có thể tìm thấy trong gói javax.imageio. Bạn có thể đọc trong một hình ảnh từ một tệp chỉ với một dòng mã:

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

Điều này sẽ cung cấp cho bạn một BufferedImage, không phải a byte[]. Để có được dữ liệu hình ảnh, bạn có thể gọi getRaster()vào BufferedImage. Điều này sẽ cung cấp cho bạn một Rasterđối tượng, có các phương thức để truy cập dữ liệu pixel (nó có một vài getPixel()/ getPixels()phương thức).

Tra cứu tài liệu API cho javax.imageio.ImageIO, java.awt.image.BufferedImage, java.awt.image.Raster, vv

ImageIO hỗ trợ một số định dạng hình ảnh theo mặc định: JPEG, PNG, BMP, WBMP và GIF. Có thể thêm hỗ trợ cho nhiều định dạng hơn (bạn cần một trình cắm thực hiện giao diện nhà cung cấp dịch vụ ImageIO).

Xem thêm hướng dẫn sau: Làm việc với hình ảnh


16

Trong trường hợp ai đó vẫn đang tìm kiếm một giải pháp mà không cần phụ thuộc và Nếu bạn có một tập tin .

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

Nói, điều gì xảy ra nếu mảng byte quá lớn có thể gây ra OOM cho heap? Có một giải pháp tương tự sẽ sử dụng JNI để lưu trữ các byte và sau này chúng ta có thể sử dụng inputStream từ dữ liệu được lưu trữ ở đó (loại bộ đệm tạm thời)?
nhà phát triển Android

14

Nếu bạn không muốn sử dụng thư viện commons-io của Apache, đoạn mã này được lấy từ lớp sun.misc.IOUtils. Nó nhanh gần gấp đôi so với triển khai phổ biến khi sử dụng 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;
}

Đây là một chút của một giải pháp kỳ lạ, chiều dài là một giới hạn trên về độ dài của mảng. Nếu bạn biết độ dài, tất cả những gì bạn cần là: byte [] output = new byte [length]; is.read (đầu ra); (nhưng hãy xem câu trả lời của tôi)
Luke Hutchison

@ luke-hutchison như tôi đã nói, đây là giải pháp của sun.misc.IOUtils. Trong các trường hợp phổ biến nhất, bạn không biết kích thước của một trả trước InputStream, vì vậy if (length == -1) length = Integer.MAX_VALUE; áp dụng. Giải pháp này hoạt động, ngay cả khi độ dài cho trước lớn hơn chiều dài của InputStream.
Kristian Kraljic

@LukeHutchison Nếu bạn biết độ dài bạn có thể xử lý nó với một vài dòng. Nếu bạn nhìn vào từng câu trả lời, mọi người đều phàn nàn rằng độ dài không được biết. Cuối cùng, một câu trả lời là tiêu chuẩn, có thể được sử dụng với Java 7 Android và không yêu cầu bất kỳ thư viện bên ngoài nào.
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: Bạn có thể tránh bộ đệm hoàn toàn.

Mã được sao chép từ http://www.examplingepot.com/egs/java.io/File2ByteArray.html (Có, nó rất dài dòng, nhưng cần một nửa kích thước bộ nhớ như giải pháp khác.)

// 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
Phụ thuộc vào việc biết kích thước trả trước.
stolsvik

2
Tất nhiên, nhưng họ nên biết kích thước: "Tôi muốn đọc một hình ảnh"
pieaveragy

1
Nếu bạn biết kích thước, thì java cung cấp mã cho bạn. xem câu trả lời của tôi hoặc google cho "DataInputStream" và đó là phương thức readFully.
dermoritz

Bạn nên thêm is.close()nếu offset < bytes.lengthhoặc InputStreamsẽ không bị đóng nếu ngoại lệ đó được ném.
Jared Rummler

3
Sau đó, tốt hơn, bạn nên sử dụng thử với các tài nguyên
pieaveragy

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

Tuy nhiên, thông thường hệ điều hành đã có đủ bộ đệm cho điều này không phải là một mối lo ngại lớn đối với các tệp nhỏ hơn. Không giống như đầu đĩa cứng sẽ đọc riêng từng byte (một đĩa cứng là một tấm kính xoay có thông tin được mã hóa từ trên đó, giống như biểu tượng kỳ lạ mà chúng ta sử dụng để lưu dữ liệu: P).
Maarten Bodewes

6
@Maarten Bodewes: hầu hết các thiết bị đều có kiểu chuyển khối, do đó, không phải mọi read () sẽ gây ra quyền truy cập thiết bị thực tế, nhưng có một cuộc gọi OS trên mỗi byte là đủ để giết hiệu năng. Trong khi góiInputStream trong một BufferedInputStreamtrước khi mã mà sẽ làm giảm các hệ điều hành các cuộc gọi và giảm thiểu những hạn chế hiệu suất đáng kể, mã mà vẫn sẽ làm công việc tay chân sao chép không cần thiết từ một bộ đệm khác.
Holger

4

Java 9 cuối cùng sẽ cung cấp cho bạn một phương thức hay:

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

4
Sự khác biệt giữa cái này và InputStram.readAllBytes()cái kia là gì?
Slava Semushin

2

Tôi biết rằng đã quá muộn nhưng ở đây tôi nghĩ là giải pháp sạch hơn, dễ đọc hơn ...

/**
 * 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
Bạn nên sử dụng thử với các tài nguyên.
Victor Stafusa

Việc dọn dẹp của bạn ở cuối cần phải được thực hiện trong một khối cuối cùng trong trường hợp có lỗi, nếu không điều này có thể gây rò rỉ bộ nhớ.
MGDavies

2

Cách Java 8 (nhờ BufferedReaderAdam Biên )

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

Lưu ý rằng giải pháp này xóa sạch trở lại vận chuyển ('\ r') và có thể không phù hợp.


4
Đó là cho String. OP đang yêu cầu byte[].
FrozenFire

Nó không chỉ \rlà một vấn đề. Phương thức này chuyển đổi các byte thành ký tự và quay lại (sử dụng bộ ký tự mặc định cho InputStreamReader). Bất kỳ byte nào không hợp lệ trong mã hóa ký tự mặc định (giả sử -1 cho UTF-8 trên Linux) sẽ bị hỏng, thậm chí có thể thay đổi số lượng byte.
seanf

Có vẻ như đây là câu trả lời tốt, nhưng định hướng văn bản. Người mua hãy cẩn thận.
Wheezil

1

Tôi đã cố chỉnh sửa câu trả lời của @ numan bằng cách sửa lỗi ghi dữ liệu rác nhưng chỉnh sửa đã bị từ chối. Mặc dù đoạn mã ngắn này không có gì xuất sắc, tôi không thể thấy câu trả lời nào tốt hơn. Đây là điều có ý nghĩa nhất đối với tôi:

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 không cần phải đóng. thử / cuối cùng các cấu trúc được bỏ qua để dễ đọc


1

Xem InputStream.available()tài liệu:

Điều đặc biệt quan trọng là nhận ra rằng bạn không được sử dụng phương pháp này để định kích thước vùng chứa và giả sử rằng bạn có thể đọc toàn bộ luồng mà không cần thay đổi kích thước vùng chứa. Những người gọi như vậy có lẽ nên viết mọi thứ họ đọc vào ByteArrayOutputStream và chuyển đổi nó thành một mảng byte. Ngoài ra, nếu bạn đang đọc từ một tệp, File.length trả về độ dài hiện tại của tệp (mặc dù giả sử độ dài của tệp không thể thay đổi có thể không chính xác, việc đọc tệp vốn không phù hợp).


1

Vì vậy, hãy bọc nó trong DataInputStream nếu điều đó không có trong bảng vì một số lý do, chỉ cần sử dụng read để gõ vào nó cho đến khi nó cung cấp cho bạn -1 hoặc toàn bộ khối bạn yêu cầu.

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

Chúng tôi đang thấy một số chậm trễ cho một vài giao dịch AWS, trong khi chuyển đổi đối tượng S3 sang ByteArray.

Lưu ý: Đối tượng S3 là tài liệu PDF (kích thước tối đa là 3 mb).

Chúng tôi đang sử dụng tùy chọn # 1 (org.apache.commons.io.IOUtils) để chuyển đổi đối tượng S3 thành ByteArray. Chúng tôi đã nhận thấy S3 cung cấp phương thức IOUtils sẵn có để chuyển đổi đối tượng S3 thành ByteArray, chúng tôi yêu cầu bạn xác nhận cách tốt nhất để chuyển đổi đối tượng S3 thành ByteArray để tránh sự chậm trễ.

Lựa chọn 1:

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

Lựa chọn 2:

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

Đồng thời cho tôi biết nếu chúng tôi có cách nào khác tốt hơn để chuyển đổi đối tượng s3 thành bytearray


0

Các trường hợp khác để có được mảng byte chính xác qua luồng, sau khi gửi yêu cầu đến máy chủ và chờ phản hồi.

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

Bạn đang thực hiện một bản sao bổ sung nếu bạn sử dụng ByteArrayOutputStream. Nếu bạn biết độ dài của luồng trước khi bạn bắt đầu đọc nó (ví dụ InputStream thực sự là FileInputStream và bạn có thể gọi file.length () trên tệp hoặc InputStream là mục nhập zipfile InputStream và bạn có thể gọi zipEntry. length ()), tốt hơn hết là ghi trực tiếp vào mảng byte [] - nó sử dụng một nửa bộ nhớ và tiết kiệm thời gian.

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

Lưu ý dòng cuối cùng ở trên xử lý các tệp bị cắt bớt trong khi luồng đang được đọc, nếu bạn cần xử lý khả năng đó, nhưng nếu tệp bị dài hơn trong khi luồng đang được đọc, nội dung trong mảng byte [] sẽ không được kéo dài để bao gồm nội dung tệp mới, mảng sẽ đơn giản được cắt ngắn theo chiều dài inputStreamLpm .


0

Tôi sử dụng cái này

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
Thêm một số lời giải thích với câu trả lời về cách câu trả lời này giúp OP khắc phục vấn đề hiện tại
ρяσѕρєя K

0

Đây là phiên bản sao chép của tôi:

@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
Mặc dù đoạn mã này có thể giải quyết câu hỏi, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn.
Ferrybig

0

Java 7 trở lên:

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

20
sun.misc.IOUtilskhông phải là Java Java 7 7. Đó là một lớp cụ thể, triển khai cụ thể có thể không có trong các triển khai JRE khác và có thể biến mất mà không có bất kỳ cảnh báo nào trong một trong các bản phát hành tiếp theo.
Holger


0

Đây là một phiên bản được tối ưu hóa, cố gắng tránh sao chép dữ liệu byte càng nhiều càng tốt:

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

Giải pháp trong Kotlin (tất nhiên cũng sẽ hoạt động trong Java), bao gồm cả hai trường hợp khi bạn biết kích thước hay không:

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

Nếu bạn biết kích thước, nó giúp bạn tiết kiệm gấp đôi bộ nhớ được sử dụng so với các giải pháp khác (trong một thời gian ngắn, nhưng vẫn có thể hữu ích). Đó là bởi vì bạn phải đọc toàn bộ luồng đến cuối, sau đó chuyển đổi nó thành một mảng byte (tương tự như ArrayList mà bạn chuyển đổi thành một mảng).

Vì vậy, nếu bạn đang ở trên Android, chẳng hạn, và bạn có một số Uri để xử lý, bạn có thể thử lấy kích thước bằng cách này:

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

Đóng và xả bos là một sự lãng phí của các nhấp chuột bàn phím. Đóng luồng đầu vào có nhiều khả năng giúp đỡ. Đọc một byte tại một thời điểm là không hiệu quả. Xem câu trả lời của numan.
akostadinov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.