/**
* 多线程下载的测试类
*/
public class Demo {
public static int threadCount = 3;
public static int runningThread = 3 ;
public static void main(String[] args) throws Exception {
// 1.连接服务器 , 获取一个文件, 获取文件的长度, 在本地创建一个大小跟服务器文件一样大的临时文件
String path = "http://192.168.1.100:8080/360.exe";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
int code = conn.getResponseCode();
if (code == 200) {
// 服务器返回的数据的长度 实际上就是文件的长度
int length = conn.getContentLength();
System.out.println("文件总长度:" + length);
// 在客户端本地 创建出来一个大小跟服务器端文件一样大小的临时文件
RandomAccessFile raf = new RandomAccessFile("setup.exe", "rwd");
// 指定创建的这个文件的长度
raf.setLength(length);
raf.close();
// 假设是3个线程去下载资源.
// 平均每一个线程下载的文件的大小.
int blockSize = length / threadCount;
for (int threadId = 1; threadId <= threadCount; threadId++) {
// 第一个线程下载的开始位置
int startIndex = (threadId - 1) * blockSize;
int endIndex = threadId * blockSize - 1;
if (threadId == threadCount) {// 最后一个线程 下载的长度 要稍微长一点
endIndex = length;
}
System.out.println("线程:" + threadId + "下载:---" + startIndex
+ "--->" + endIndex);
new DownloadThread(path, threadId, startIndex, endIndex)
.start();
}
} else {
System.out.println("服务器错误.");
}
}
/**
* 下载文件的子线程 每一个线程 下载对应位置的文件
*
* @author Administrator
*
*/
public static class DownloadThread extends Thread {
private int threadId;
private int startIndex;
private int endIndex;
private String path;
/**
* @param path
* 下载文件在服务器上的路径
* @param threadId
* 线程id
* @param startIndex
* 线程下载的开始位置
* @param endIndex
* 线程下载的结束位置.
*/
public DownloadThread(String path, int threadId, int startIndex,
int endIndex) {
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.path = path;
}
@Override
public void run() {
try {
// 检查是否存在 记录下载长度的文件 ,如果存在读取这个文件的数据.
File tempFile = new File(threadId + ".txt");
if (tempFile.exists() && tempFile.length() > 0) {
FileInputStream fis = new FileInputStream(tempFile);
byte[] temp = new byte[1024];
int leng = fis.read(temp);
String downloadLen = new String(temp, 0, leng);
int downloadlenInt = Integer.parseInt(downloadLen);
startIndex = downloadlenInt;//修改下载的真实的开始位置.
fis.close();
}
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestMethod("GET");
// 重要: 请求服务器下载部分的文件 指定文件的位置.
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
+ endIndex);
System.out.println("线程真实下载:" + threadId + "下载:---" + startIndex
+ "--->" + endIndex);
conn.setConnectTimeout(5000);
int code = conn.getResponseCode(); // 从服务器请求全部资源 200 ok
// 如果从服务器请求部分资源 206 ok
if (code == 206) {
InputStream is = conn.getInputStream();// 已经设置了 请求的位置
RandomAccessFile raf = new RandomAccessFile("setup.exe",
"rwd");
// 随机写文件的时候 从哪个位置开始写
raf.seek(startIndex);// 定位文件
int len = 0;
byte[] buffer = new byte[1024];
int total = 0;// 已经下载的数据长度
while ((len = is.read(buffer)) != -1) {
RandomAccessFile file = new RandomAccessFile(threadId
+ ".txt", "rwd");// 作用: 记录当前线程下载的数据长度
raf.write(buffer, 0, len);
total += len;
//System.out.println("线程:" + threadId + "total:" + total);
file.write(( total+startIndex+"").getBytes());//记录的是 下载位置.
file.close();
}
is.close();
raf.close();
System.out.println("线程:" + threadId + "下载完毕了...");
} else {
System.out.println("线程:" + threadId + "下载失败...");
}
File deleteFile = new File(threadId+".txt");
deleteFile.delete();//当线程下载完毕后 清楚掉 下载的记录
//如何去判断应用程序已经下载完毕.
} catch (Exception e) {
e.printStackTrace();
}finally{
runningThread --;
if(runningThread==0){//所有的线程 已经执行完毕了.
for(int i= 1;i<=3;i++){
File file = new File(i+".txt");
file.delete();
}
System.out.println("文件下载完毕 ,删除所有的下载记录.");
}
}
}
}
RandomAccessFile raf = new RandomAccessFile("setup.exe","rwd");
这里的rwd是同步写入数据到磁盘。就是不缓存,直接写。
还有一个是rws。rws是将文件的元数据也同步写入磁盘。