</pre><pre name="code" class="html">web开发中涉及到多线程下载文件,源代码如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
/*
* 多线程下载的测试类
*/
public class Demo {
public static int threadCount = 3 ;
public static int runningThread = 3 ;
public static void main(String[] args) throws Exception {
//1·连接服务器,获取一个文件,获取文件的长度,在本地创建一个大小跟服务器文件一样大的临时文件
//模拟服务器的文件可以放在本地server的webapps/Root文件夹下,文件最好是.exe程序!
String path = "http://211.87.234.10:8080/drivethelife.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==>"+length) ;
//使用API 在本地创建一个大小跟服务器端文件一样大小的临时文件 第一个参数是文件名,第二个是mode模式
RandomAccessFile raf = new RandomAccessFile("drivethelife.exe", "rwd") ;
//指定创建文件的长度
raf.setLength(length) ;
raf.close() ;
//假设是3个线程去下载资源
//平均每个线程下载的文件大小
int blockSize = length / threadCount ;
System.out.println("blockSize==>"+blockSize) ;
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("服务器错误") ;
}
}
/*
* 下载文件的子线程 每一个线程下载对应位置的文件
*/
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) {
super();
this.path = path ;
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
@Override
public void run() {
try {
//检查是否存在记录下载长度的文件,如果存在则读取这个文件的数据并添加到startIndex。
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) ; //fis的输入流读到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") ;
//请求服务器下载部分的文件 指定文件的位置。
//若需要下载特定长度的资源,则需要HTTP请求头字段Range去设置 !!
conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex) ;
System.out.println("线程真实下载:"+threadId+"下载:--"+startIndex+"--->"+endIndex) ;
conn.setConnectTimeout(5000) ;
int code = conn.getResponseCode() ;//若是从服务器请求全部资源 200 OK 如果请求部分资源 206 OK
System.out.println("code==>"+code) ;
if(code == 206){
InputStream is = conn.getInputStream() ;//若前面没有设置Range.返回全部资源,已经设置了请求的位置,返回的是当前位置对应的文件的输入流
//输出到本地文件的对应位置 使用java API RandomAccessFile 使用指针指定到对应位置,然后下载
RandomAccessFile raf = new RandomAccessFile("drivethelife.exe", "rwd") ;
//随机写文件的时候从哪个位置开始写
raf.seek(startIndex) ;//定位文件
int len = 0;
byte[] buffer = new byte[10240000] ;
int total = 0 ;//已经下载的数据长度
while((len=is.read(buffer))!=-1){
RandomAccessFile file = new RandomAccessFile(threadId+".txt","rwd") ;//记录当前线程下载的数据长度
raf.write(buffer, 0, len) ;
total +=len ;
file.write(String.valueOf(total+startIndex+"").getBytes()) ;//记录的是下载的位置.
file.close() ;
}
is.close() ;
raf.close() ;
System.out.println("线程:"+threadId+"下载完毕了。。。") ;
}else{
System.out.println("线程:"+threadId+"下载失败。。。") ;
}
} catch (Exception e) {
// TODO Auto-generated catch block
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("文件下载完毕,并删除所有的下载记录") ;
}
}
}
}
}