免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2914 | 回复: 0

[Android] Java中使用RandomAccessFile类实现多线程下载 [复制链接]

论坛徽章:
80
20周年集字徽章-庆
日期:2020-10-28 14:09:1215-16赛季CBA联赛之北京
日期:2020-10-28 13:32:5315-16赛季CBA联赛之北控
日期:2020-10-28 13:32:4815-16赛季CBA联赛之天津
日期:2020-10-28 13:13:35黑曼巴
日期:2020-10-28 12:29:1520周年集字徽章-周	
日期:2020-10-31 15:10:0720周年集字徽章-20	
日期:2020-10-31 15:10:07ChinaUnix元老
日期:2015-09-29 11:56:3020周年集字徽章-年
日期:2020-10-28 14:14:56
发表于 2015-10-22 11:18 |显示全部楼层
多线程下载文件的注意点主要有:

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为下载的开始点
  1. import java.io.File;
  2. import java.io.InputStream;
  3. import java.io.RandomAccessFile;
  4. import java.net.HttpURLConnection;
  5. import java.net.URL;

  6. public class Test {
  7.         /**
  8.          * 文件下载的路径
  9.          */
  10.         private static final String PATH = "http://localhost:8080/test.exe";
  11.         /**
  12.          * 下载的线程个数
  13.          */
  14.         private static final int COUNT = 3;
  15.         /**
  16.          * 创建一个文件,将远程文件写入该文件
  17.          */
  18.         private File f = new File("C:\\Users\\Administrator\\Desktop\\test.exe");
  19.        
  20.         public void download() throws Exception{
  21.                 URL url = new URL(PATH);
  22.                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  23.                 //使用get请求
  24.                 conn.setRequestMethod("GET");
  25.                 //设置连接超时时间为5秒
  26.                 conn.setConnectTimeout(5000);
  27.                 //得到服务器返回的响应码
  28.                 int code = conn.getResponseCode();
  29.                 //响应码为200,代表请求资源成功(前提是请求整个资源,而不是资源的某一部分)
  30.                 if(code == 200){
  31.                         //得到文件的总大小
  32.                         int length = conn.getContentLength();
  33.                         //新建一个随机访问的文件
  34.                         RandomAccessFile raf = new RandomAccessFile(f, "rw");
  35.                         //第一个参数为文件类型,第二个参数为模式,可以为"r","rw","rws","rwd"
  36.                         raf = new RandomAccessFile(f, "rw");
  37.                         //设置随机文件的大小为服务器端文件的大小
  38.                         raf.setLength(length);
  39.                         System.out.println("文件总大小为:" + length);
  40.                         //计算每个线程下载的块的大小
  41.                         int blockSize = length / COUNT;
  42.                         for(int i = 0; i < COUNT; i++){
  43.                                 //每个线程的起始下载点
  44.                                 int startPos = blockSize * i;
  45.                                 //每个线程的结束下载点
  46.                                 int endPos = blockSize * (i + 1) - 1;
  47.                                 //如果是最后一条线程,将其下载的终止点设为文件的终点
  48.                                 if(i == COUNT){
  49.                                         endPos = length;
  50.                                 }
  51.                                 System.out.println("线程" + i + "下载的部分为:" + startPos +"---" + endPos);
  52.                                 //开启线程分别下载不同的部分
  53.                                 new DownThread(i, startPos, endPos).start();
  54.                         }
  55.                 }
  56.         }
  57.        
  58.         /**
  59.          * 下载文件的线程
  60.          * @author Administrator
  61.          *
  62.          */
  63.         class DownThread extends Thread{
  64.                 //线程ID
  65.                 private int threadId;
  66.                 //线程下载的起始点
  67.                 private int startPos;
  68.                 //线程下载的结束点
  69.                 private int endPos;
  70.                
  71.                 public DownThread(int threadId, int startPos, int endPos) {
  72.                         this.threadId = threadId;
  73.                         this.startPos = startPos;
  74.                         this.endPos = endPos;
  75.                 }

  76.                 @Override
  77.                 public void run(){
  78.                         try {
  79.                                 URL url = new URL(PATH);
  80.                                 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  81.                                 conn.setConnectTimeout(5000);
  82.                                 conn.setRequestMethod("GET");
  83.                                 //设置头部的参数,表示请求服务器资源的某一部分
  84.                                 conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
  85.                                 //设置了上面的头信息后,响应码为206代表请求资源成功,而不再是200
  86.                                 int code = conn.getResponseCode();
  87.                                 if(code == 206){
  88.                                         InputStream is = conn.getInputStream();
  89.                                         int hasRead = 0;
  90.                                         byte[] buf = new byte[1024];
  91.                                         //这里要注意新创建一个RandomAccessFile对象,而不能重复使用download方法中创建的
  92.                                         RandomAccessFile raf = new RandomAccessFile(f, "rw");
  93.                                         //将写文件的指针指向下载的起始点
  94.                                         raf.seek(startPos);
  95.                                         while((hasRead = is.read(buf)) > 0) {
  96.                                                 raf.write(buf, 0, hasRead);
  97.                                         }
  98.                                         is.close();
  99.                                         System.out.println("线程" + threadId + "下载完毕...");
  100.                                 }
  101.                         } catch (Exception e) {
  102.                                 e.printStackTrace();
  103.                         }
  104.                 }
  105.         }
  106.        
  107.         public static void main(String[] args) {
  108.                 try {
  109.                         new Test().download();
  110.                 } catch (Exception e) {
  111.                         e.printStackTrace();
  112.                 }
  113.         }
  114. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP