我正在尝试使用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,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(),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的内容长度相匹配.有什么我错过的吗?
解决方法
我不熟悉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),因此“输入结束”哨兵值不起作用.用a替换null
private static ByteArrayWrapper END = new ByteArrayWrapper(new byte[]{});
在适当的地方会解决这个问题.