2009-09-08 34 views
12

Đây có phải là:Làm thế nào để khởi tạo một ByteBuffer nếu bạn không biết có bao nhiêu byte để phân bổ trước?

ByteBuffer buf = ByteBuffer.allocate(1000); 

... cách duy nhất để khởi tạo một ByteBuffer?

Điều gì xảy ra nếu tôi không biết mình cần phân bổ bao nhiêu byte ..?

Edit: Thông tin chi tiết:

tôi là chuyển đổi định dạng file một hình ảnh vào một tập tin TIFF. Vấn đề là định dạng tập tin bắt đầu có thể là bất kỳ kích thước nào, nhưng tôi cần phải ghi dữ liệu trong TIFF đến ít cuối. Vì vậy, tôi đang đọc những thứ tôi cuối cùng sẽ in tập tin TIFF vào ByteBuffer đầu tiên vì vậy tôi có thể đặt tất cả mọi thứ trong Little Endian, sau đó tôi sẽ viết nó vào outfile. Tôi đoán kể từ khi tôi biết IFD dài bao lâu, tiêu đề là, và tôi có thể tìm ra số byte trong mỗi mặt phẳng ảnh, tôi có thể sử dụng nhiều ByteBuffer trong toàn bộ quá trình này.

Trả lời

7

Phụ thuộc.

Thư viện

Định dạng tệp chuyển đổi có xu hướng là vấn đề được giải quyết cho hầu hết các miền có vấn đề. Ví dụ:

  • Batik có thể chuyển mã giữa các định dạng hình ảnh khác nhau (bao gồm TIFF).
  • Apache POI có thể chuyển đổi giữa các định dạng bảng tính văn phòng.
  • Flexmark có thể tạo HTML từ Đánh dấu.

Danh sách dài. Câu hỏi đầu tiên nên là, "Điều gì library có thể thực hiện tác vụ này?" Nếu hiệu suất là một xem xét, thời gian của bạn có thể tốt hơn dành tối ưu hóa một gói hiện có để đáp ứng nhu cầu của bạn hơn là viết một công cụ khác. (Như một phần thưởng, những người khác được hưởng lợi từ việc tập trung.)


Quantities Known

  • Đọc một tập tin? Phân bổ file.size() byte.
  • Sao chép chuỗi? Phân bổ string.length() byte.
  • Sao chép gói TCP? Phân bổ 1500 byte, chẳng hạn.

Quantities Unknown

Khi số lượng các byte thực sự là không rõ, bạn có thể làm một vài điều:

  • Hãy đoán.
  • Phân tích các tập dữ liệu mẫu thành bộ đệm; sử dụng độ dài trung bình.

Ví dụ

Java StringBuffer, trừ trường hợp được hướng dẫn, sử dụng một kích thước bộ đệm ban đầu để giữ 16 ký tự. Khi 16 ký tự được lấp đầy, một mảng mới, dài hơn được cấp phát và sau đó sao chép 16 ký tự gốc. Nếu số StringBuffer có kích thước ban đầu là 1024 ký tự, thì việc phân bổ lại sẽ không xảy ra sớm hoặc thường xuyên.

Tối ưu hóa

Dù bằng cách nào, đây có thể là tối ưu hóa sớm. Thông thường, bạn sẽ cấp phát một số lượng byte được đặt khi bạn muốn giảm số lượng phân bổ lại bộ nhớ trong được thực hiện.

Rất có thể đây sẽ là nút cổ chai của ứng dụng.

+3

Một' StringBuffer' hoạt động khác nhau. Một 'ByteBuffer' sẽ chỉ ném một' BufferOverflowException' nếu bạn cố gắng thêm nhiều hơn nữa. – bvdb

4

Ý tưởng là nó chỉ là bộ đệm - không phải toàn bộ dữ liệu. Đó là một điểm tạm nghỉ cho dữ liệu khi bạn đọc một đoạn, xử lý nó (có thể viết nó ở một nơi khác). Vì vậy, hãy phân bổ cho chính mình một "chunk" đủ lớn và thông thường sẽ không có vấn đề gì.

Bạn đang mong đợi vấn đề gì?

10

Các loại địa điểm bạn sẽ sử dụng ByteBuffer nói chung là các loại địa điểm mà bạn sẽ sử dụng một mảng byte (cũng có kích thước cố định). Với I/O đồng bộ, bạn thường sử dụng mảng byte, với I/O không đồng bộ, ByteBuffers được sử dụng thay thế.

Nếu bạn cần phải đọc một số lượng không rõ của dữ liệu bằng ByteBuffer, xem xét sử dụng một vòng lặp với đệm của bạn và thêm dữ liệu vào một ByteArrayOutputStream khi bạn đọc nó. Khi bạn hoàn tất, hãy gọi toByteArray() để nhận mảng byte cuối cùng.

Bất cứ khi nào bạn không hoàn toàn chắc chắn về kích thước (hoặc kích thước tối đa) của đầu vào đã cho, hãy đọc trong một vòng lặp (có thể sử dụng ByteArrayOutputStream, nhưng nếu không thì chỉ xử lý dữ liệu dưới dạng luồng) là cách duy nhất để xử lý nó. Nếu không có một số loại vòng lặp, tất cả dữ liệu còn lại sẽ bị mất.

Ví dụ:

final byte[] buf = new byte[4096]; 
int numRead; 

// Use try-with-resources to auto-close streams. 
try(
    final FileInputStream fis = new FileInputStream(...); 
    final ByteArrayOutputStream baos = new ByteArrayOutputStream() 
) { 
    while ((numRead = fis.read(buf)) > 0) { 
    baos.write(buf, 0, numRead); 
    } 

    final byte[] allBytes = baos.toByteArray(); 

    // Do something with the data. 
} 
catch(final Exception e) { 
    // Do something on failure... 
} 

Nếu bạn thay vì muốn viết Java int s, hoặc những thứ khác mà không phải là byte liệu, bạn có thể quấn bạn ByteArrayOutputStream trong một DataOutputStream:

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
DataOutputStream dos = new DataOutputStream(baos); 

while (thereAreMoreIntsFromSomewhere()) { 
    int someInt = getIntFromSomewhere(); 
    dos.writeInt(someInt); 
} 

byte[] allBytes = baos.toByteArray();  
+0

Bạn có thể cho ví dụ về điều này bằng cách sử dụng ByteArrayOutputStream không? Như chúng ta hãy nói cho một số nguyên? –

+0

@PaulaKristin Hãy khám phá ngay bây giờ (tôi cũng đã sửa liên kết 'ByteArrayOutputStream' bị hỏng) –

Các vấn đề liên quan