2016-02-17 14 views
10

Tôi đang cố tải xuống tệp pdf bằng cách sử dụng URLConnection. Đây là cách tôi thiết lập đối tượng kết nối.Tải xuống tệp PDF bằng cách sử dụng BlockingQueue

URL serverUrl = new URL(url); 
urlConnection = (HttpURLConnection) serverUrl.openConnection(); 
urlConnection.setDoInput(true); 
urlConnection.setRequestMethod("GET"); 
urlConnection.setRequestProperty("Content-Type", "application/pdf"); 
urlConnection.setRequestProperty("ENCTYPE", "multipart/form-data"); 
String contentLength = urlConnection.getHeaderField("Content-Length"); 

Tôi thu được luồng đầu vào từ đối tượng kết nối.

bufferedInputStream = new BufferedInputStream(urlConnection.getInputStream()); 

Và luồng đầu ra để ghi nội dung tệp.

File dir = new File(context.getFilesDir(), mFolder); 
if(!dir.exists()) dir.mkdir(); 
final File f = new File(dir, String.valueOf(documentName)); 
f.createNewFile(); 
final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(f, true)); //true for appendMode 

BlockingQueue được tạo để các chuỗi hoạt động đọc và ghi có thể truy cập hàng đợi.

final BlockingQueue<ByteArrayWrapper> blockingQueue = new ArrayBlockingQueue<ByteArrayWrapper>(MAX_VALUE,true); 
final byte[] dataBuffer = new byte[MAX_VALUE]; 

Bây giờ tạo chuỗi để đọc dữ liệu từ InputStream.

Thread readerThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
     try { 
      int count = 0; 
      while((count = bufferedInputStream.read(dataBuffer, 0, dataBuffer.length)) != -1) { 
       ByteArrayWrapper byteArrayWrapper = new ByteArrayWrapper(dataBuffer); 
       byteArrayWrapper.setBytesReadCount(count); 
       blockingQueue.put(byteArrayWrapper); 
      } 
      blockingQueue.put(null); //end of file 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } finally { 
       try { 
       bufferedInputStream.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
}); 

Bây giờ, chuỗi ghi sẽ đọc nội dung tệp đó.

Thread writerThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
     try { 
      while(true) { 
       ByteArrayWrapper byteWrapper = blockingQueue.take(); 
       if(null == byteWrapper) break; 
       bufferedOutputStream.write(byteWrapper.getBytesRead(), 0, byteWrapper.getBytesReadCount()); 
      } 
      bufferedOutputStream.flush(); 
     } catch(Exception e) { 
       e.printStackTrace(); 
     } finally { 
       try { 
       bufferedOutputStream.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
     } 
     } 
}); 

Cuối cùng, chủ đề được bắt đầu.

readerThread.start(); 
writerThread.start(); 

Về mặt lý thuyết, nên đọc tệp từ InputStream và lưu tệp đó vào tệp đích. Tuy nhiên, trên thực tế, nó tạo ra tệp pdf trống. Tại một số thời điểm khác, nó cho thấy ngoại lệ định dạng pdf không hợp lệ. Kích thước tệp phù hợp với độ dài nội dung của InputStream. Có điều gì tôi đang thiếu?

Trả lời

5

Tôi không quen với ByteArrayWrapper. Liệu nó chỉ giữ một tham chiếu đến mảng, như thế này?

public class ByteArrayBuffer { 
    final private byte[] data; 

    public ByteArrayBuffer(byte[] data) { 
     this.data = data; 
    } 

    public byte[] getBytesRead() { 
     return data; 
    } 

    /*...etc...*/ 
} 

Nếu có. đó sẽ là vấn đề: tất cả các đối tượng ByteArrayWrapper được hỗ trợ bởi cùng một mảng. Liên tục được ghi đè bởi người viết. Mặc dù BlockingQueue đã làm việc chăm chỉ để xuất bản từng đối tượng một cách an toàn từ chuỗi này sang chủ đề khác.

Sửa chữa đơn giản nhất có thể là làm cho ByteArrayWrapper không thay đổi có hiệu quả tức là không thay đổi nó sau khi xuất bản lên một chuỗi khác. Lấy một bản sao của mảng xây dựng sẽ được đơn giản nhất:

public ByteArrayWrapper(byte[] data) { 
    this.data = Arrays.copyOf(data, data.length); 
} 

Một vấn đề khác là "BlockingQueue không chấp nhận các yếu tố vô giá trị" (xem BlockingQueue docs), và do đó, "cuối đầu vào" sentinel giá trị không công việc. Thay thế null bằng một số

private static ByteArrayWrapper END = new ByteArrayWrapper(new byte[]{}); 

ở những nơi thích hợp sẽ khắc phục điều đó.

Bằng cách thực hiện những thay đổi đó cho bản sao mã, tôi có thể truy xuất bản sao trung thực của tệp PDF.

+0

Vâng, đúng vậy.Bạn đúng https://android.googlesource.com/platform/packages/inputmethods/LatinIME/+/03118a2/java/src/com/android/inputmethod/latin/ByteArrayWrapper.java – xAF

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