import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @author EX-QINCIDONG001 多线程下载文件。 思想:开启5个线程,每个线程下载文件大小的1/5,<br>
* 每个线程生成的文件以文件名_编号作为文件名。<br>
* 每个线程结束后都检查自己是否是最后一个线程。<br>
* 如果是最后一个线程,就启动合并文件的线程<br>
* 用RandomAccessFile类,有追加文件的方法。<br>
* 扫描所有的文件,合并为一个文件。
*
* 例:<br>
* Thread File Name File Size
* Thread-1 test_1.mp3 300kb
* Thread-2 test_2.mp3 300kb
* Thread-3 test_3.mp3 200kb
*
* 最终的文件:test.mp3
*/
publicclass ThreadDownloadFile {
// 要下载的文件的URL
private String fileUrl;
// 要保存的文件名
private String saveName;
// 要创建的线程数量
privatestaticfinalintTHREAD_COUNT = 5;
// 保存线程运行的状态(0标识线程还在运行,1标识结束)
Map<Integer, Integer> threadStatusMap = new HashMap<Integer, Integer>();
public ThreadDownloadFile(String fileUrl,String saveName) {
this.fileUrl = fileUrl;
this.saveName = saveName;
// 初始化线程运行状态
for (int i=0;i<THREAD_COUNT;i++) {
// key:线程编号,value:线程运行状态
threadStatusMap.put(i, 0);
}
}
privatevoid download() throws IOException {
URL url = new URL(this.fileUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setAllowUserInteraction(true);
conn.connect();
// 文件总的长度
int contentLength = conn.getContentLength();
// 每个线程应该分配的长度
int partLength = contentLength / this.THREAD_COUNT + 1;
conn.disconnect();
System.out.println("开始下载文件...");
for (int i = 0; i < this.THREAD_COUNT; i++) {
int length = partLength;
if (i == this.THREAD_COUNT - 1) { // 最后一个的长度
length = contentLength - partLength * i;
}
int index1 = saveName.lastIndexOf("/");
int index2 = saveName.lastIndexOf(".");
String partFileName = saveName.substring(0, index1+1)
+ saveName.substring(index1+1, index2) + "_"+(i + 1)
+ saveName.substring(index2, saveName.length());
DownloadThread dt = new DownloadThread(conn,contentLength,this.THREAD_COUNT,i,length,i*length, url, partFileName,threadStatusMap,this.saveName);
dt.start();
}
}
/**
* @param args
*/
publicstaticvoid main(String[] args) {
// String saveName = "http://www.a.b/c/d.mp3";
// int index1 = saveName.lastIndexOf("/");
// int index2 = saveName.lastIndexOf(".");
// int i = 0;
// String partFileName = saveName.substring(0, index1+1)
// + saveName.substring(index1+1, index2) +"_"+ (i + 1)
// + saveName.substring(index2, saveName.length());
// System.out.println(partFileName);
String fileUrl = "http://www.baidu.com";//"http://localhost:8080/filedownload/download1.jsp";
String saveName = "D:/Users/ex-qincidong001/Desktop/outlook邮件归类.docx";
ThreadDownloadFile tdf = new ThreadDownloadFile(fileUrl,saveName);
try {
tdf.download();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class DownloadThread extends Thread {
// 总长度
privateintcontentLength;
// 线程数
privateintthreadNum;
// 当前线程编号
privateintcurrentThreadNum;
privateintlength;
privateintoffset;
private URL url;
private String partFileName;
// 要保存的文件名
private String saveName;
private Map<Integer,Integer> threadStatusMap;
HttpURLConnection conn;
DownloadThread(HttpURLConnection conn,int contentLength,int threadNum,int currentThreadNum,int length,int offset, URL url, String partFileName,Map<Integer,Integer> threadStatusMap,String saveName) {
this.conn = conn;
this.contentLength = contentLength;
this.threadNum = threadNum;
this.currentThreadNum = currentThreadNum;
this.length = length;
this.offset = offset;
this.url = url;
this.partFileName = partFileName;
this.threadStatusMap = threadStatusMap;
this.saveName = saveName;
}
publicvoid run() {
System.out.println("线程【" +this.currentThreadNum + "】开启...");
// HttpURLConnection conn;
try {
conn = (HttpURLConnection) url.openConnection();
conn.setAllowUserInteraction(true);
conn.setRequestProperty("RANGE", "bytes=" + offset );
conn.connect();
// 设置断点续传的开始位置
FileOutputStream fos = new FileOutputStream(partFileName);
InputStream is = conn.getInputStream();
byte[] data = newbyte[1024];
int len = -1;
int readSize = 0;
while ((len = is.read(data)) != -1) {
readSize += len;
if (readSize > length) { // 只读取length长度
len = len - (readSize - length);
}
fos.write(data, 0, len);
if (readSize > length) {
break;
}
}
fos.flush();
is.close();
// 将线程运行状态改为1(结束)
this.threadStatusMap.remove(currentThreadNum);
this.threadStatusMap.put(currentThreadNum, 1);
// 检查是否全部想线程都运行完毕
boolean flag = true;
Set<Integer> keys = this.threadStatusMap.keySet();
Iterator<Integer> its = keys.iterator();
while (its.hasNext()) {
Integer key = its.next();
Integer value = this.threadStatusMap.get(key);
if (value == 0) {
flag = false;
break;
}
}
System.out.println("线程【" +this.currentThreadNum + "】结束...");
if (flag) { // 所有的下载线程均结束,可以开始合并文件的线程
MergeThread mt = new MergeThread(this.contentLength,this.threadNum,this.saveName);
mt.start();
System.out.println("文件下载完毕...\n文件保存位置:" + this.saveName);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 合并文件的线程。
* @author EX-QINCIDONG001
*
*/
class MergeThread extends Thread {
// 文件总长度
privateintcontentLength;
// 线程的数量,以便于知道,生成了几个子文件。
privateintthreadNum;
// 要保存的最终的文件名
private String saveName;
public MergeThread(int contentLength,int threadNum,String saveName) {
this.contentLength = contentLength;
this.threadNum = threadNum;
this.saveName = saveName;
}
publicvoid run() {
int index1 = saveName.lastIndexOf("/");
int index2 = saveName.lastIndexOf(".");
RandomAccessFile accessFile = null;
try {
accessFile = new RandomAccessFile(saveName,"rw");
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 每个线程应该分配的长度
int partLength = contentLength / this.threadNum + 1;
for (int i=0;i<threadNum;i++) {
// 子文件文件名
String partFileName = saveName.substring(0, index1+1)
+ saveName.substring(index1+1, index2) +"_"+ (i + 1)
+ saveName.substring(index2, saveName.length());
int length = partLength;
if (i == this.threadNum - 1) { // 最后一个的长度
length = contentLength - partLength * i;
}
try {
accessFile.seek(i*length);
FileInputStream fis = new FileInputStream(partFileName);
byte[] data = newbyte[1024];
int len = -1;
while ((len = fis.read(data)) != -1) {
accessFile.write(data,0,len);
}
fis.close();
accessFile.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
相关推荐
java多线程断点下载文件 ,文档介绍及代码实现
java多线程下载文件源码,只能用炫酷来形容,感兴趣就下载看看吧
Java多线程读大文件 java多线程写文件:多线程往队列中写入数据
Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式上传文件Java多线程设计模式...
java实现多线程下载文件功能,通过线程池管理,实现下载文件速度快,安全。
实现文件多线程下载,可以指定下载线程数。可以用于学习
java多线程下载源代码 java多线程下载源代码
java多线程文件传输 java多线程文件传输
刚学完多线程和线程池,以及线程爱好者。 使用场景及目标: 大文件的快速下载,经测试在100M带宽的网络下,下载一个40M的文件,不超过两秒钟,当然还得根据自己电脑的配置来讲。 其他说明: 文件如果特别小,而...
演示了JAVA中的多线程 界面简单 需要请拿去
4.为了杀死线程还能继续下载的情况下,从本地文件上读取已经下载文件的开始位置 a)创建保存记录结束位置的文件 b)读取文件 c)将流转换为字符 d)获取记录位置 e)把记录位置赋给开始位置 5.当你的n个线程都下载完毕的...
详细的讲解了java多线程的原理,并配有代码进行实战,适合java初学者和想对多线程有进一步了解的人。
Java多线程断点下载文件,可以运行的,
java多线程下载网站,网站整站下载器,这是java源码和需要的包,jsoup
java多线程加队列上传文件_后台处理
本程序是在原有基础上逐步完善的,第一版:...详细文档请看: http://www.open-open.com/home/space.php?uid=183&do=blog&id=8799 本程序很适合在主机间批量传输文件和目录,参数可控
Java代码,根据URL方式下载单个文件或者图片,根据文件大小进行分批启动多线程下载!
主要为大家详细介绍了Java多线程下载文件的实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
利用JAVA编写的多线程运行实例 压缩文件,可直接运行 ...利用JAVA编写的多线程运行实例 压缩文件,可直接运行利用JAVA编写的多线程运行实例 压缩文件,可直接运行利用JAVA编写的多线程运行实例 压缩文件,可直接运行