2009-03-12 37 views
7

Tôi đang cố gắng tìm ra lý do tại sao đoạn mã đặc biệt này không hoạt động đối với tôi. Tôi đã có một applet đó là nghĩa vụ phải đọc một pdf. Và hiển thị nó với một thư viện pdf renderer, nhưng đối với một số lý do khi tôi đọc trong các tập tin .pdf mà ngồi trên máy chủ của tôi, họ sẽ bị hỏng. Tôi đã thử nghiệm nó bằng cách viết các tập tin trở lại một lần nữa.Java: Đọc một tệp pdf từ URL vào Byte array/ByteBuffer trong applet

Tôi đã thử xem applet trong cả IE và Firefox và các tệp bị hỏng xảy ra. Điều thú vị là, khi tôi cố gắng xem applet trong Safari (đối với Windows), tập tin thực sự là tốt! Tôi hiểu JVM có thể khác, nhưng tôi vẫn bị mất. Tôi đã biên soạn trong Java 1.5. Các JVM là 1,6. Đoạn trích đọc tệp dưới đây.

public static ByteBuffer getAsByteArray(URL url) throws IOException { 
     ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(); 

     URLConnection connection = url.openConnection(); 
     int contentLength = connection.getContentLength(); 
     InputStream in = url.openStream(); 
     byte[] buf = new byte[512]; 
     int len; 
     while (true) { 
      len = in.read(buf); 
      if (len == -1) { 
       break; 
      } 
      tmpOut.write(buf, 0, len); 
     } 
     tmpOut.close(); 
     ByteBuffer bb = ByteBuffer.wrap(tmpOut.toByteArray(), 0, 
             tmpOut.size()); 
     //Lines below used to test if file is corrupt 
     //FileOutputStream fos = new FileOutputStream("C:\\abc.pdf"); 
     //fos.write(tmpOut.toByteArray()); 
     return bb; 
} 

Tôi phải thiếu thứ gì đó và tôi đã đập đầu để cố gắng tìm ra. Bất kỳ trợ giúp nào cũng được đánh giá rất cao. Cảm ơn.


Edit: Để làm rõ thêm hoàn cảnh của tôi, sự khác biệt trong các tập tin trước khi tôi đọc sau đó với đoạn và sau đó, là những cái tôi ra sau khi đọc nhỏ hơn đáng kể so với ban đầu là. Khi mở chúng, chúng không được nhận dạng dưới dạng tệp .pdf. Không có ngoại lệ được ném mà tôi bỏ qua, và tôi đã cố gắng đỏ bừng vô ích.

Đoạn mã này hoạt động trong Safari, nghĩa là các tệp được đọc toàn bộ, không có sự khác biệt về kích thước và có thể được mở bằng bất kỳ trình đọc .pdf nào. Trong IE và Firefox, các tệp luôn bị hỏng, luôn có cùng kích thước nhỏ hơn.

Tôi đã theo dõi biến len (khi đọc tệp 59kb), hy vọng xem có bao nhiêu byte được đọc tại mỗi vòng lặp. Trong IE và Firefox, tại 18kb, in.read (buf) trả về -1 như thể tệp đã kết thúc. Safari không làm điều này.

Tôi sẽ tiếp tục và tôi đánh giá cao tất cả các đề xuất từ ​​trước tới nay.

+0

Khi bạn nói tệp bị hỏng, bạn có ý nghĩa gì? Nếu bạn so sánh với bản gốc, điều gì khác biệt? – Eddie

+0

Vui lòng trả lời câu hỏi thứ hai của Eddie. Ngoài ra, giá trị của contentLength có chính xác không? – jdigital

Trả lời

11

Chỉ trong trường hợp những thay đổi nhỏ tạo sự khác biệt, hãy thử này:

public static ByteBuffer getAsByteArray(URL url) throws IOException { 
    URLConnection connection = url.openConnection(); 
    // Since you get a URLConnection, use it to get the InputStream 
    InputStream in = connection.getInputStream(); 
    // Now that the InputStream is open, get the content length 
    int contentLength = connection.getContentLength(); 

    // To avoid having to resize the array over and over and over as 
    // bytes are written to the array, provide an accurate estimate of 
    // the ultimate size of the byte array 
    ByteArrayOutputStream tmpOut; 
    if (contentLength != -1) { 
     tmpOut = new ByteArrayOutputStream(contentLength); 
    } else { 
     tmpOut = new ByteArrayOutputStream(16384); // Pick some appropriate size 
    } 

    byte[] buf = new byte[512]; 
    while (true) { 
     int len = in.read(buf); 
     if (len == -1) { 
      break; 
     } 
     tmpOut.write(buf, 0, len); 
    } 
    in.close(); 
    tmpOut.close(); // No effect, but good to do anyway to keep the metaphor alive 

    byte[] array = tmpOut.toByteArray(); 

    //Lines below used to test if file is corrupt 
    //FileOutputStream fos = new FileOutputStream("C:\\abc.pdf"); 
    //fos.write(array); 
    //fos.close(); 

    return ByteBuffer.wrap(array); 
} 

Bạn quên đóng fos mà có thể dẫn đến tập tin đó là ngắn hơn nếu ứng dụng của bạn vẫn chạy hoặc là đột ngột chấm dứt. Ngoài ra, tôi đã thêm tạo ByteArrayOutputStream với kích thước ban đầu phù hợp. (Nếu không Java sẽ phải cấp phát nhiều lần mảng và sao chép mới, cấp phát một mảng mới và sao chép, tốn kém.) Thay thế giá trị 16384 bằng một giá trị phù hợp hơn. 16k có lẽ là nhỏ cho một PDF, nhưng tôi không biết làm thế nào nhưng kích thước "trung bình" là bạn mong đợi để tải về.

Vì bạn sử dụng toByteArray() hai lần (ngay cả khi một trong mã chẩn đoán), tôi đã gán nó cho một biến. Cuối cùng, mặc dù nó không tạo ra bất kỳ sự khác biệt nào, khi bạn gói toàn bộ mảng trong một ByteBuffer, bạn chỉ cần cung cấp mảng byte đó. Cung cấp bù đắp 0 và độ dài là dư thừa.

Lưu ý rằng nếu bạn đang tải xuống lớn tệp PDF theo cách này, thì hãy đảm bảo rằng JVM của bạn đang chạy với số lượng lớn đủ để bạn có đủ chỗ cho kích thước tệp lớn nhất nhiều lần. Phương pháp bạn đang sử dụng giữ toàn bộ tập tin trong bộ nhớ, đó là OK miễn là bạn có thể đủ khả năng bộ nhớ đó.:)

0

Bạn đã thử một số flush() trước khi đóng luồng tmpOut để đảm bảo tất cả các byte được ghi ra?

+1

close() thực hiện lệnh flush() – jdigital

0

Bạn hoàn toàn tích cực mã này không phải là ném IOExceptions mà bạn không nhìn thấy bởi vì bạn bỏ qua chúng từ người gọi của phương pháp này hoặc một số như vậy? Mã như là có vẻ tốt với tôi.

0

Hãy thử chạy Fiddler (Proxy gỡ lỗi HTTP miễn phí) và xem có bất kỳ điều gì thú vị không - chắc chắn bạn sẽ muốn đảm bảo rằng máy chủ đang gửi toàn bộ luồng nhưng bạn cũng muốn kiểm tra độ dài nội dung vv Bạn có thể sử dụng Fiddler với bất kỳ trình duyệt nào nhưng tôi muốn sử dụng IE vì proxy sẽ được cấu hình tự động.

0

Tôi nghĩ rằng tôi đã có cùng một vấn đề như bạn, nhưng nó bật ra vấn đề của tôi là tôi giả sử bạn luôn nhận được bộ đệm đầy đủ cho đến khi bạn nhận được gì. Nhưng bạn không cho rằng điều đó. Các ví dụ trên mạng (ví dụ: java2s/tutorial) sử dụng BufferedInputStream. Nhưng điều đó không tạo ra bất kỳ sự khác biệt nào đối với tôi.

Bạn có thể kiểm tra xem bạn có thực sự nhận được tệp đầy đủ trong vòng lặp của mình hay không. Hơn vấn đề sẽ ở trong ByteArrayOutputStream.

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