| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
wgd7
10年前发布

Java实现文件断点续传

import java.io.File;  import java.io.IOException;  import java.io.RandomAccessFile;  import java.net.HttpURLConnection;  import java.net.URL;    public class DownloadFile {        /**       * @param args       */      static int len;//线程平均下载文件长度      static int bn ;//每个线程写入文件的字节数      static int tn; //线程数      static String urlt;//下载地址      static String fileName;      static RandomAccessFile osf; //文件操作      public static void main(String[] args) {          // TODO Auto-generated method stub            try {              urlt = "http://192.168.16.77:8080/Stargreat/html/baidu player";              fileName = "C:\" + urlt.split("//")[1].split("/")[urlt.split("//")[1].split("/").length-1];              System.out.println(fileName);              URL url = new URL(urlt);              HttpURLConnection http = (HttpURLConnection) url.openConnection();                /**               * 此处设定5个线程下载一个文件tn = 5;               * 判断平均每个线程需下载文件长度:               */              System.out.println("file size:" + http.getContentLength());              tn = 3;                       len = http.getContentLength() / tn ;//舍去余数(余数自动舍去)计算每个线程应下载平均长度,最后一个线程再加上余数,则是整个文件的长度,              File f = new File(fileName);              if (f.exists()){                  f.delete();                  osf = new RandomAccessFile(f, "rw");                  osf.seek(http.getContentLength()-1);                  osf.write(0);              }else{                  osf = new RandomAccessFile(f, "rw");                  osf.seek(http.getContentLength()-1);                  osf.write(0);              }              System.out.println("temp 文件长度:" + f.length());              Thread t;//下载子线程,              for (int j = 0; j < tn; j++) {                  if(j == tn - 1){//如果最后一个线程则加上余数长度字节                      bn = len + (http.getContentLength() % tn);                  }else{                      bn = len;                  }                  System.out.println("t"+ j + "线程下载长度:" + bn + "起始字节:" + len*j);                  t = new DT(                          j,                          urlt,                          fileName,                          len*j,                          bn                    );                  t.start();              }            } catch (IOException e) {              // TODO Auto-generated catch block              e.printStackTrace();          }      }    }

import java.io.File;  import java.io.FileNotFoundException;  import java.io.IOException;  import java.io.InputStream;  import java.io.RandomAccessFile;  import java.net.HttpURLConnection;  import java.net.MalformedURLException;  import java.net.URL;  import java.util.Date;    public class DT extends Thread {        String urlt;//下载地址      int startl;//子线程读取/写入起始字节      int end;//子线程写入结束字节长度      String fileName;      RandomAccessFile osf;      public DT(int i ,String url,String fileName,int start,int end){          this.setName("t"+i); //子线程名称          this.urlt = url; //下载地址          this.fileName = fileName;          this.startl = start; //子线程读取/写入起始字节          this.end = end;//子线程写入结束字节长度      }      public void run(){              try {                  osf = new RandomAccessFile(fileName, "rw");                  URL url = new URL(urlt);                  HttpURLConnection http2 = (HttpURLConnection) url.openConnection();                  http2.setRequestProperty("User-Agent","NetFox");                     /*                   * 断点续传和多线程下载的关键代码关键位置:即设置断点                   * http2.setRequestProperty("RANGE", "bytes="+startl+"-");//设置断点位置,向服务器请求从文件的哪个字节开始读取。                   * osf.seek(startl);//设置本地文件从哪个字节开始写入                   * 如果是单线程,则首先要判断下载文件是否已经存在 及DownloadFile.java 里的 fileName = "C:\eclipse.zip";                   * 如果存在则开始断点续传,方法同多线程:                   * 因为断点续传是从上次传输中断的字节开始,则首先要得到上次中断的位置,既是文件长度(针对单线程)f.length()                   * 然后设置HTTP请求头属性RANGE,该属性告知服务器从哪个自己开始读取文件。                   * 设置本地文件写入起始字节,及接从上次传输断点继续写入(断点续传)                   * osf.seek(offset) 该方法设定从offset后一个字节开始写入文件                   * 注意:多线程不能用文件长度做为写文件起始字节,需有配置文件记录上次读写的位置,迅雷下载既是使用该种方法。                   *                   */                  http2.setRequestProperty("RANGE", "bytes="+startl+"-");//设置断点位置,向服务器请求从文件的哪个字节开始读取。                  osf.seek(startl);//设置本地文件从哪个字节开始写入                    InputStream input = http2.getInputStream();                  byte b[] = new byte[1024];//设置缓冲池,每次只读1024字节                  Date d = new Date();//子线程开始下载时间                  int l;//计算子线程读取和写入的文件长度,当长度大于每个子线程平均下载长度则终止线程                  int i;                  l = 0;                  System.out.println(this.getName() + " 开始下载。。。");                  while ( (i = input.read(b,0,1024)) != -1 && l < end){    //线程下载字节长度控制误差小于缓冲池大小,本示例为缓冲池1024字节                      osf.write(b, 0, i);                      b = new byte[1024];//重新赋值,避免重新读入旧内容                      l += i;                           }                  Date d2 = new Date();//子线程结束下载时间                  System.out.println(this.getName() + " 线程耗时: " + (d2.getTime() - d.getTime())/1000 + " 秒,实际共下载:" + l + "字节");//子线程下载耗时(秒)              } catch (FileNotFoundException e1) {                  // TODO Auto-generated catch block                  e1.printStackTrace();              } catch (MalformedURLException e) {                  // TODO Auto-generated catch block                  e.printStackTrace();              } catch (IOException e) {                  // TODO Auto-generated catch block                  e.printStackTrace();              }      }  }