- 论坛徽章:
- 80
|
多线程下载文件的注意点主要有:
1、确定每个线程下载的文件大小,用这种方法计算:
先获取整个文件的大小length,然后除以线程个数count得到每个线程下载的块大小为blockSize = length / count,每个线程的起始下载点为:startPos = blockSize * i,结束下载点为:endPos = blockSize * (i + 1) - 1,其中最后一个线程下载的结束点应该为文件末尾
2、随机访问文件RandomAccessFile类的使用方法,该类的实例化需要两个参数,第一个可以使一个文件File类,也可以是文件的path,String类,第二个参数代表文件写入的模式,可以为"r","rw","rws","rwd"之一
3、在每个线程中写文件的时候都需要实例化一个RandomAccessFile的实例,而不能重复使用同一个RandomAccessFile
4、在设置请求参数时,获取服务器的响应码会有所不同,如果请求的是一整个资源,则请求成功的响应码是200,若请求的是某个资源的部分时,请求成功返回的响应码是206,这一点需要注意,另外,在每个线程中下载一个文件的不同部分时,需要设置请求的头字段:conn.setRequestProperty("Range", "bytes=12345-13456");设置该头字段代表请求服务器资源的12345到13456这部分的内容
另外,在每个线程下载之前,需要将RandomAccessFile的实例的指针指向下载的开始点,使用如下方法:
raf.seek(startPos); 其中raf为RandomAccessFile类的对象,startPos为下载的开始点- import java.io.File;
- import java.io.InputStream;
- import java.io.RandomAccessFile;
- import java.net.HttpURLConnection;
- import java.net.URL;
- public class Test {
- /**
- * 文件下载的路径
- */
- private static final String PATH = "http://localhost:8080/test.exe";
- /**
- * 下载的线程个数
- */
- private static final int COUNT = 3;
- /**
- * 创建一个文件,将远程文件写入该文件
- */
- private File f = new File("C:\\Users\\Administrator\\Desktop\\test.exe");
-
- public void download() throws Exception{
- URL url = new URL(PATH);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- //使用get请求
- conn.setRequestMethod("GET");
- //设置连接超时时间为5秒
- conn.setConnectTimeout(5000);
- //得到服务器返回的响应码
- int code = conn.getResponseCode();
- //响应码为200,代表请求资源成功(前提是请求整个资源,而不是资源的某一部分)
- if(code == 200){
- //得到文件的总大小
- int length = conn.getContentLength();
- //新建一个随机访问的文件
- RandomAccessFile raf = new RandomAccessFile(f, "rw");
- //第一个参数为文件类型,第二个参数为模式,可以为"r","rw","rws","rwd"
- raf = new RandomAccessFile(f, "rw");
- //设置随机文件的大小为服务器端文件的大小
- raf.setLength(length);
- System.out.println("文件总大小为:" + length);
- //计算每个线程下载的块的大小
- int blockSize = length / COUNT;
- for(int i = 0; i < COUNT; i++){
- //每个线程的起始下载点
- int startPos = blockSize * i;
- //每个线程的结束下载点
- int endPos = blockSize * (i + 1) - 1;
- //如果是最后一条线程,将其下载的终止点设为文件的终点
- if(i == COUNT){
- endPos = length;
- }
- System.out.println("线程" + i + "下载的部分为:" + startPos +"---" + endPos);
- //开启线程分别下载不同的部分
- new DownThread(i, startPos, endPos).start();
- }
- }
- }
-
- /**
- * 下载文件的线程
- * @author Administrator
- *
- */
- class DownThread extends Thread{
- //线程ID
- private int threadId;
- //线程下载的起始点
- private int startPos;
- //线程下载的结束点
- private int endPos;
-
- public DownThread(int threadId, int startPos, int endPos) {
- this.threadId = threadId;
- this.startPos = startPos;
- this.endPos = endPos;
- }
- @Override
- public void run(){
- try {
- URL url = new URL(PATH);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(5000);
- conn.setRequestMethod("GET");
- //设置头部的参数,表示请求服务器资源的某一部分
- conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
- //设置了上面的头信息后,响应码为206代表请求资源成功,而不再是200
- int code = conn.getResponseCode();
- if(code == 206){
- InputStream is = conn.getInputStream();
- int hasRead = 0;
- byte[] buf = new byte[1024];
- //这里要注意新创建一个RandomAccessFile对象,而不能重复使用download方法中创建的
- RandomAccessFile raf = new RandomAccessFile(f, "rw");
- //将写文件的指针指向下载的起始点
- raf.seek(startPos);
- while((hasRead = is.read(buf)) > 0) {
- raf.write(buf, 0, hasRead);
- }
- is.close();
- System.out.println("线程" + threadId + "下载完毕...");
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- public static void main(String[] args) {
- try {
- new Test().download();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
复制代码 |
|