用java多线程断点续传实践
2009-09-24 00:00:00 来源:WEB开发网OutputStream的write方法和上面InputStream的read方法有类似的参数,byte b[]是输出数据的来源,off标识了开始位置,len是数据长度。
public synchronized void write(byte b[], int off, int len) throws IOException;
在往临时文件的outputStream中写数据的时候,我会加上一个计数器,每满5000个比特就往文件中flush一下(代码⑦处)。
对于输出流的flush,有些要注意的地方,在程序中有三个地方调用了outputStream.flush()。第一个是在循环的读取网络数据并往 outputStream中写入的时候,每满5000个byte就flush一下(代码⑦处);第二个是循环之后(代码⑧处),这时候正常的读取写入操作已经完成,但是outputStream中还有没有刷入磁盘的数据,所以要flush一下才能关闭连接;第三个就是在异常中的flush(代码⑨处),因为如果发生了连接超时或者读取数据超时的话,就会直接跑到catch的exception中去,这个时候outputStream中的数据如果不 flush的话,重新连接的时候这部分数据就会丢失了。另外,当抛出异常,重新连接的时候,下载的起始位置也要重新设置(代码④处),count就是用来标识已经下载的字节数的,把count+startPosition就是新一次连接需要的下载起始位置了。
3、现在每个分段的下载线程都顺利结束了,也都创建了相应的临时文件,接下来在主线程中会对临时文件进行合并,并写入目标文件,最后删除临时文件。这部分很简单,就是一个对所有下载线程进行遍历的过程。这里outputStream也有两次flush,与上面类似,不再赘述。
/** *//**author by http://www.bt285.cn http://www.guihua.org */
private void tempFileToTargetFile(ChildThread[] childThreads) {
try {
BufferedOutputStream outputStream = new BufferedOutputStream(
new FileOutputStream(fileDir + fileName));
// 遍历所有子线程创建的临时文件,按顺序把下载内容写入目标文件中
for (int i = 0; i < threadNum; i++) {
if (statusError) {
for (int k = 0; k < threadNum; k++) {
if (childThreads[k].tempFile.length() == 0)
childThreads[k].tempFile.delete();
}
System.out.println("本次下载任务不成功,请重新设置线程数。");
break;
}
BufferedInputStream inputStream = new BufferedInputStream(
new FileInputStream(childThreads[i].tempFile));
System.out.println("Now is file " + childThreads[i].id);
int len = 0;
int count = 0;
byte[] b = new byte[1024];
while ((len = inputStream.read(b)) != -1) {
count += len;
outputStream.write(b, 0, len);
if ((count % 5000) == 0) {
outputStream.flush();
}
// b = new byte[1024];
}
inputStream.close();
// 删除临时文件
if (childThreads[i].status == ChildThread.STATUS_HAS_FINISHED) {
childThreads[i].tempFile.delete();
}
}
outputStream.flush();
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
更多精彩
赞助商链接