【问题标题】:PDF file download using BlockingQueue使用 BlockingQueue 下载 PDF 文件
【发布时间】:2016-02-17 10:09:47
【问题描述】:

我正在尝试使用 URLConnection 下载 pdf 文件。下面是我设置连接对象的方法。

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

我从连接对象中获得了输入流。

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

以及写入文件内容的输出流。

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 被创建以便执行读写操作的线程可以访问队列。

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

现在创建线程从 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();
              }
          }
       }
 });

现在编写器线程读取这些文件内容。

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

最后,线程启动了。

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

理论上它应该从 InputStream 中读取文件并将其保存到目标文件中。但是,实际上,它会生成空白的 pdf 文件。在其他时候,它显示无效的 pdf 格式异常。文件大小与 InputStream 的内容长度相匹配。有什么我想念的吗?

【问题讨论】:

    标签: java android blockingqueue


    【解决方案1】:

    我不熟悉ByteArrayWrapper。它只是像这样持有对数组的引用吗?

    public class ByteArrayBuffer {
        final private byte[] data;
    
        public ByteArrayBuffer(byte[] data) {
            this.data = data;
        }
    
        public byte[] getBytesRead() {
            return data;
        }
    
        /*...etc...*/
    } 
    

    如果是这样。这就是问题所在:所有ByteArrayWrapper 对象都由同一个数组支持。它被作者反复覆盖。尽管BlockingQueue 做了艰苦的工作,将每个对象从一个线程安全地发布到另一个线程。

    最简单的解决方法可能是使ByteArrayWrapper 有效地不可变,即在将其发布到另一个线程后不要更改它。在构造时获取数组的副本是最简单的:

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

    另一个问题是“BlockingQueue 不接受空元素”(参见BlockingQueue docs),因此“输入结束”标记值不起作用。将null 替换为

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

    在适当的地方会解决这个问题。

    通过对代码副本进行这些更改,我能够检索到 PDF 文件的忠实副本。

    【讨论】:

    【解决方案2】:

    尝试使用 Android DownloadManager (http://developer.android.com/reference/android/app/DownloadManager.html) 它用于在后台处理长时间运行的 HTTP 请求。 这里不需要考虑接收到的字节数,进度会显示在通知栏中。

    这里有很好的教程:http://blog.vogella.com/2011/06/14/android-downloadmanager-example/

    【讨论】:

      猜你喜欢
      • 2016-09-12
      • 2017-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 2016-04-07
      相关资源
      最近更新 更多