今天学习了使用RandomAccessFile类实现多线程的下载。实现代码如下:
ThreadDownLoad.java
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class ThreadDownLoad {
//定义线程的个数
public static final int Thread_COunt = 3;
static String path = "http://192.168.1.105:8080/2.docx";
public static void main(String[] args) {
//1、请求服务器,
URL url;
try {
url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setReadTimeout(5000);
if(conn.getResponseCode() == 200){
//获取文件的大小
int totalSize = conn.getContentLength();
String fileName = getFileName(path);
System.out.println(fileName+"-------");
RandomAccessFile raf = new RandomAccessFile("F://fileUpload//"+getFileName(path), "rw");
System.out.println("文件大小:"+totalSize);
//为文件设置指定大小
raf.setLength(totalSize);
//定义平均没法线程需要下载的大小
int blockSize = totalSize / Thread_COunt;
//定义每个线程开始位置和结束位置
int startSize = 0;
int endSize = 0;
for(int threadId = 0;threadId<Thread_COunt;threadId++){
startSize = threadId * blockSize;
endSize = (threadId+1)*blockSize-1;
//如果文件不能平均分,那么线程3将下载所有剩余的内容。
if(threadId == Thread_COunt-1 && totalSize % Thread_COunt!=0){
endSize = totalSize -1;
}
new Downloader(threadId, startSize, endSize).start();
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String getFileName(String path){
int num = path.lastIndexOf("/")+1;
return path.substring(num);
}
static class Downloader extends Thread{
//多线程下载,要获取startId、endId、threadId
private int threadId;
private int endId;
private int startId;
private int currentId;
public Downloader(int threadId,int startId,int endId){
this.endId = endId;
this.startId = startId;
this.threadId = threadId;
this.currentId = startId;
}
@Override
public void run() {
//在run方法中执行下载任务
try {
File tempFile = new File("F://fileUpload//"+threadId+".position");
//当再次读取文件的时候,先判断临时文件是否存在。
if(tempFile.exists()&&tempFile.length()>0){
//如果存在,重新给给startId进行赋值。
BufferedReader bis = new BufferedReader
(new InputStreamReader(new FileInputStream(tempFile)));
currentId = Integer.parseInt(bis.readLine());
System.out.println("线程:"+threadId+"文件再次读取时的开始位置--"+currentId);
}
URL url = new URL(path);
System.out.println("线程:"+threadId+"--开始位置currentId----"+currentId);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestProperty("Range", "bytes:"+currentId+"-"+endId);
int code = conn.getResponseCode();
RandomAccessFile raf = new RandomAccessFile("F://fileUpload//"+getFileName(path), "rw");
raf.seek(currentId);
//获取服务器中的部分内容
//为了实现每个线程下载东西都有固定的位置,所以必须告诉服务器,每个线程从什么位置下载到什么位置
if(code == 206){
InputStream is = conn.getInputStream();
//设置每个线程读取文件的开始位置
byte[] b = new byte[1024*1024];
int len =0;
while((len = is.read(b))!=-1){
raf.write(b, 0, len);
currentId += len; //获取每次循环读取的结束值
//定义一个输出流
//rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
RandomAccessFile fos = new RandomAccessFile(tempFile, "rws");
System.out.println("线程:"+threadId+"当前写入文件的数据currentId==="+currentId);
fos.write((currentId+"").getBytes());
fos.close();
sleep(300);
}
}
raf.close();
//循环完毕之后删除临时文件
if(tempFile.exists()&&tempFile.length()>0){
System.out.println("文件名:"+tempFile.getName());
boolean flag= tempFile.delete();
System.out.println("线程"+threadId+"删除成功?"+tempFile.delete());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}