• 断点续传的原理


    断点续传的原理

    断点续传的原理

    其实断点续传的原理很简单,就是在 Http 的请求上和一般的下载有所不同而已。 
    打个比方,浏览器请求服务器上的一个文时,所发出的请求如下: 
    假设服务器域名为 wwww.sjtu.edu.cn,文件名为 down.zip。 
    GET /down.zip HTTP/1.1 
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms- 
    excel, application/msword, application/vnd.ms-powerpoint, */* 
    Accept-Language: zh-cn 
    Accept-Encoding: gzip, deflate 
    User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) 
    Connection: Keep-Alive

    服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:

    200 
    Content-Length=106786028 
    Accept-Ranges=bytes 
    Date=Mon, 30 Apr 2001 12:56:11 GMT 
    ETag=W/"02ca57e173c11:95b" 
    Content-Type=application/octet-stream 
    Server=Microsoft-IIS/5.0 
    Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT

    所谓断点续传,也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给 Web 服务器的时候要多加一条信息 -- 从哪里开始。 
    下面是用自己编的一个"浏览器"来传递请求信息给 Web 服务器,要求从 2000070 字节开始。 
    GET /down.zip HTTP/1.0 
    User-Agent: NetFox 
    RANGE: bytes=2000070- 
    Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

    仔细看一下就会发现多了一行 RANGE: bytes=2000070- 
    这一行的意思就是告诉服务器 down.zip 这个文件从 2000070 字节开始传,前面的字节不用传了。 
    服务器收到这个请求以后,返回的信息如下: 
    206 
    Content-Length=106786028 
    Content-Range=bytes 2000070-106786027/106786028 
    Date=Mon, 30 Apr 2001 12:55:20 GMT 
    ETag=W/"02ca57e173c11:95b" 
    Content-Type=application/octet-stream 
    Server=Microsoft-IIS/5.0 
    Last-Modified=Mon, 30 Apr 2001 12:55:20 GMT

    和前面服务器返回的信息比较一下,就会发现增加了一行: 
    Content-Range=bytes 2000070-106786027/106786028 
    返回的代码也改为 206 了,而不再是 200 了。

    知道了以上原理,就可以进行断点续传的编程了。


    Java 实现断点续传的关键几点

    1. (1) 用什么方法实现提交 RANGE: bytes=2000070-。 
      当然用最原始的 Socket 是肯定能完成的,不过那样太费事了,其实 Java 的 net 包中提供了这种功能。代码如下: 

      URL url = new URL("http://www.sjtu.edu.cn/down.zip"); 
      HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection(); 

      // 设置 User-Agent 
      httpConnection.setRequestProperty("User-Agent","NetFox"); 
      // 设置断点续传的开始位置 
      httpConnection.setRequestProperty("RANGE","bytes=2000070"); 
      // 获得输入流 
      InputStream input = httpConnection.getInputStream(); 

      从输入流中取出的字节流就是 down.zip 文件从 2000070 开始的字节流。大家看,其实断点续传用 Java 实现起来还是很简单的吧。接下来要做的事就是怎么保存获得的流到文件中去了。

    2. 保存文件采用的方法。 
      我采用的是 IO 包中的 RandAccessFile 类。 
      操作相当简单,假设从 2000070 处开始保存文件,代码如下: 
      RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw"); 
      long nPos = 2000070; 
      // 定位文件指针到 nPos 位置 
      oSavedFile.seek(nPos); 
      byte[] b = new byte[1024]; 
      int nRead; 
      // 从输入流中读入字节流,然后写到文件中 
      while((nRead=input.read(b,0,1024)) > 0) 

      oSavedFile.write(b,0,nRead); 

    怎么样,也很简单吧。接下来要做的就是整合成一个完整的程序了。包括一系列的线程控制等等。


    断点续传内核的实现

    主要用了 6 个类,包括一个测试类。 
    SiteFileFetch.java 负责整个文件的抓取,控制内部线程 (FileSplitterFetch 类 )。 
    FileSplitterFetch.java 负责部分文件的抓取。 
    FileAccess.java 负责文件的存储。 
    SiteInfoBean.java 要抓取的文件的信息,如文件保存的目录,名字,抓取文件的 URL 等。 
    Utility.java 工具类,放一些简单的方法。 
    TestMethod.java 测试类。 

    下面是源程序:

    1. /*  
    2.  /* 
    3.  * SiteFileFetch.java  
    4.  */   
    5.  package NetFox;   
    6.  import java.io.*;   
    7.  import java.net.*;   
    8.  public class SiteFileFetch extends Thread {   
    9.  SiteInfoBean siteInfoBean = null; // 文件信息 Bean   
    10.  long[] nStartPos; // 开始位置  
    11.  long[] nEndPos; // 结束位置  
    12.  FileSplitterFetch[] fileSplitterFetch; // 子线程对象  
    13.  long nFileLength; // 文件长度  
    14.  boolean bFirst = true; // 是否第一次取文件  
    15.  boolean bStop = false; // 停止标志  
    16.  File tmpFile; // 文件下载的临时信息  
    17.  DataOutputStream output; // 输出到文件的输出流  
    18.  public SiteFileFetch(SiteInfoBean bean) throws IOException   
    19.  {   
    20.  siteInfoBean = bean;   
    21.  //tmpFile = File.createTempFile ("zhong","1111",new File(bean.getSFilePath()));   
    22.  tmpFile = new File(bean.getSFilePath()+File.separator + bean.getSFileName()+".info");  
    23.  if(tmpFile.exists ())   
    24.  {   
    25.  bFirst = false;   
    26.  read_nPos();   
    27.  }   
    28.  else   
    29.  {   
    30.  nStartPos = new long[bean.getNSplitter()];   
    31.  nEndPos = new long[bean.getNSplitter()];   
    32.  }   
    33.  }   
    34.  public void run()   
    35.  {   
    36.  // 获得文件长度  
    37.  // 分割文件  
    38.  // 实例 FileSplitterFetch   
    39.  // 启动 FileSplitterFetch 线程  
    40.  // 等待子线程返回  
    41.  try{   
    42.  if(bFirst)   
    43.  {   
    44.  nFileLength = getFileSize();   
    45.  if(nFileLength == -1)   
    46.  {   
    47.  System.err.println("File Length is not known!");   
    48.  }   
    49.  else if(nFileLength == -2)   
    50.  {   
    51.  System.err.println("File is not access!");   
    52.  }   
    53.  else   
    54.  {   
    55.  for(int i=0;i<nStartPos.length;i++)   
    56.  {   
    57.  nStartPos[i] = (long)(i*(nFileLength/nStartPos.length));   
    58.  }   
    59.  for(int i=0;i<nEndPos.length-1;i++)   
    60.  {   
    61.  nEndPos[i] = nStartPos[i+1];   
    62.  }   
    63.  nEndPos[nEndPos.length-1] = nFileLength;   
    64.  }   
    65.  }   
    66.  // 启动子线程  
    67.  fileSplitterFetch = new FileSplitterFetch[nStartPos.length];   
    68.  for(int i=0;i<nStartPos.length;i++)   
    69.  {   
    70.  fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),   
    71.  siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),   
    72.  nStartPos[i],nEndPos[i],i);   
    73.  Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = "   
    74.  + nEndPos[i]);   
    75.  fileSplitterFetch[i].start();   
    76.  }   
    77.  // fileSplitterFetch[nPos.length-1] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),  
    78.  siteInfoBean.getSFilePath() + File.separator   
    79.  + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1);   
    80.  // Utility.log("Thread " +(nPos.length-1) + ",nStartPos = "+nPos[nPos.length-1]+",  
    81.  nEndPos = " + nFileLength);   
    82.  // fileSplitterFetch[nPos.length-1].start();   
    83.  // 等待子线程结束  
    84.  //int count = 0;   
    85.  // 是否结束 while 循环  
    86.  boolean breakWhile = false;   
    87.  while(!bStop)   
    88.  {   
    89.  write_nPos();   
    90.  Utility.sleep(500);   
    91.  breakWhile = true;   
    92.  for(int i=0;i<nStartPos.length;i++)   
    93.  {   
    94.  if(!fileSplitterFetch[i].bDownOver)   
    95.  {   
    96.  breakWhile = false;   
    97.  break;   
    98.  }   
    99.  }   
    100.  if(breakWhile)   
    101.  break;   
    102.  //count++;   
    103.  //if(count>4)   
    104.  // siteStop();   
    105.  }   
    106.  System.err.println("文件下载结束!");   
    107.  }   
    108.  catch(Exception e){e.printStackTrace ();}   
    109.  }   
    110.  // 获得文件长度  
    111.  public long getFileSize()   
    112.  {   
    113.  int nFileLength = -1;   
    114.  try{   
    115.  URL url = new URL(siteInfoBean.getSSiteURL());   
    116.  HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();  
    117.  httpConnection.setRequestProperty("User-Agent","NetFox");   
    118.  int responseCode=httpConnection.getResponseCode();   
    119.  if(responseCode>=400)   
    120.  {   
    121.  processErrorCode(responseCode);   
    122.  return -2; //-2 represent access is error   
    123.  }   
    124.  String sHeader;   
    125.  for(int i=1;;i++)   
    126.  {   
    127.  //DataInputStream in = new DataInputStream(httpConnection.getInputStream ());   
    128.  //Utility.log(in.readLine());   
    129.  sHeader=httpConnection.getHeaderFieldKey(i);   
    130.  if(sHeader!=null)   
    131.  {   
    132.  if(sHeader.equals("Content-Length"))   
    133.  {   
    134.  nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));   
    135.  break;   
    136.  }   
    137.  }   
    138.  else   
    139.  break;   
    140.  }   
    141.  }   
    142.  catch(IOException e){e.printStackTrace ();}   
    143.  catch(Exception e){e.printStackTrace ();}   
    144.  Utility.log(nFileLength);   
    145.  return nFileLength;   
    146.  }   
    147.  // 保存下载信息(文件指针位置)  
    148.  private void write_nPos()   
    149.  {   
    150.  try{   
    151.  output = new DataOutputStream(new FileOutputStream(tmpFile));   
    152.  output.writeInt(nStartPos.length);   
    153.  for(int i=0;i<nStartPos.length;i++)   
    154.  {   
    155.  // output.writeLong(nPos[i]);   
    156.  output.writeLong(fileSplitterFetch[i].nStartPos);   
    157.  output.writeLong(fileSplitterFetch[i].nEndPos);   
    158.  }   
    159.  output.close();   
    160.  }   
    161.  catch(IOException e){e.printStackTrace ();}   
    162.  catch(Exception e){e.printStackTrace ();}   
    163.  }   
    164.  // 读取保存的下载信息(文件指针位置)  
    165.  private void read_nPos()   
    166.  {   
    167.  try{   
    168.  DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));   
    169.  int nCount = input.readInt();   
    170.  nStartPos = new long[nCount];   
    171.  nEndPos = new long[nCount];   
    172.  for(int i=0;i<nStartPos.length;i++)   
    173.  {   
    174.  nStartPos[i] = input.readLong();   
    175.  nEndPos[i] = input.readLong();   
    176.  }   
    177.  input.close();   
    178.  }   
    179.  catch(IOException e){e.printStackTrace ();}   
    180.  catch(Exception e){e.printStackTrace ();}   
    181.  }   
    182.  private void processErrorCode(int nErrorCode)   
    183.  {   
    184.  System.err.println("Error Code : " + nErrorCode);   
    185.  }   
    186.  // 停止文件下载  
    187.  public void siteStop()   
    188.  {   
    189.  bStop = true;   
    190.  for(int i=0;i<nStartPos.length;i++)   
    191.  fileSplitterFetch[i].splitterStop();   
    192.  }   
    193.  }   
    194.    
    1. /*  
    2.  /* 
    3.  * SiteFileFetch.java  
    4.  */   
    5.  package NetFox;   
    6.  import java.io.*;   
    7.  import java.net.*;   
    8.  public class SiteFileFetch extends Thread {   
    9.  SiteInfoBean siteInfoBean = null; // 文件信息 Bean   
    10.  long[] nStartPos; // 开始位置  
    11.  long[] nEndPos; // 结束位置  
    12.  FileSplitterFetch[] fileSplitterFetch; // 子线程对象  
    13.  long nFileLength; // 文件长度  
    14.  boolean bFirst = true; // 是否第一次取文件  
    15.  boolean bStop = false; // 停止标志  
    16.  File tmpFile; // 文件下载的临时信息  
    17.  DataOutputStream output; // 输出到文件的输出流  
    18.  public SiteFileFetch(SiteInfoBean bean) throws IOException   
    19.  {   
    20.  siteInfoBean = bean;   
    21.  //tmpFile = File.createTempFile ("zhong","1111",new File(bean.getSFilePath()));   
    22.  tmpFile = new File(bean.getSFilePath()+File.separator + bean.getSFileName()+".info");  
    23.  if(tmpFile.exists ())   
    24.  {   
    25.  bFirst = false;   
    26.  read_nPos();   
    27.  }   
    28.  else   
    29.  {   
    30.  nStartPos = new long[bean.getNSplitter()];   
    31.  nEndPos = new long[bean.getNSplitter()];   
    32.  }   
    33.  }   
    34.  public void run()   
    35.  {   
    36.  // 获得文件长度  
    37.  // 分割文件  
    38.  // 实例 FileSplitterFetch   
    39.  // 启动 FileSplitterFetch 线程  
    40.  // 等待子线程返回  
    41.  try{   
    42.  if(bFirst)   
    43.  {   
    44.  nFileLength = getFileSize();   
    45.  if(nFileLength == -1)   
    46.  {   
    47.  System.err.println("File Length is not known!");   
    48.  }   
    49.  else if(nFileLength == -2)   
    50.  {   
    51.  System.err.println("File is not access!");   
    52.  }   
    53.  else   
    54.  {   
    55.  for(int i=0;i<nStartPos.length;i++)   
    56.  {   
    57.  nStartPos[i] = (long)(i*(nFileLength/nStartPos.length));   
    58.  }   
    59.  for(int i=0;i<nEndPos.length-1;i++)   
    60.  {   
    61.  nEndPos[i] = nStartPos[i+1];   
    62.  }   
    63.  nEndPos[nEndPos.length-1] = nFileLength;   
    64.  }   
    65.  }   
    66.  // 启动子线程  
    67.  fileSplitterFetch = new FileSplitterFetch[nStartPos.length];   
    68.  for(int i=0;i<nStartPos.length;i++)   
    69.  {   
    70.  fileSplitterFetch[i] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),   
    71.  siteInfoBean.getSFilePath() + File.separator + siteInfoBean.getSFileName(),   
    72.  nStartPos[i],nEndPos[i],i);   
    73.  Utility.log("Thread " + i + " , nStartPos = " + nStartPos[i] + ", nEndPos = "   
    74.  + nEndPos[i]);   
    75.  fileSplitterFetch[i].start();   
    76.  }   
    77.  // fileSplitterFetch[nPos.length-1] = new FileSplitterFetch(siteInfoBean.getSSiteURL(),  
    78.  siteInfoBean.getSFilePath() + File.separator   
    79.  + siteInfoBean.getSFileName(),nPos[nPos.length-1],nFileLength,nPos.length-1);   
    80.  // Utility.log("Thread " +(nPos.length-1) + ",nStartPos = "+nPos[nPos.length-1]+",  
    81.  nEndPos = " + nFileLength);   
    82.  // fileSplitterFetch[nPos.length-1].start();   
    83.  // 等待子线程结束  
    84.  //int count = 0;   
    85.  // 是否结束 while 循环  
    86.  boolean breakWhile = false;   
    87.  while(!bStop)   
    88.  {   
    89.  write_nPos();   
    90.  Utility.sleep(500);   
    91.  breakWhile = true;   
    92.  for(int i=0;i<nStartPos.length;i++)   
    93.  {   
    94.  if(!fileSplitterFetch[i].bDownOver)   
    95.  {   
    96.  breakWhile = false;   
    97.  break;   
    98.  }   
    99.  }   
    100.  if(breakWhile)   
    101.  break;   
    102.  //count++;   
    103.  //if(count>4)   
    104.  // siteStop();   
    105.  }   
    106.  System.err.println("文件下载结束!");   
    107.  }   
    108.  catch(Exception e){e.printStackTrace ();}   
    109.  }   
    110.  // 获得文件长度  
    111.  public long getFileSize()   
    112.  {   
    113.  int nFileLength = -1;   
    114.  try{   
    115.  URL url = new URL(siteInfoBean.getSSiteURL());   
    116.  HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();  
    117.  httpConnection.setRequestProperty("User-Agent","NetFox");   
    118.  int responseCode=httpConnection.getResponseCode();   
    119.  if(responseCode>=400)   
    120.  {   
    121.  processErrorCode(responseCode);   
    122.  return -2; //-2 represent access is error   
    123.  }   
    124.  String sHeader;   
    125.  for(int i=1;;i++)   
    126.  {   
    127.  //DataInputStream in = new DataInputStream(httpConnection.getInputStream ());   
    128.  //Utility.log(in.readLine());   
    129.  sHeader=httpConnection.getHeaderFieldKey(i);   
    130.  if(sHeader!=null)   
    131.  {   
    132.  if(sHeader.equals("Content-Length"))   
    133.  {   
    134.  nFileLength = Integer.parseInt(httpConnection.getHeaderField(sHeader));   
    135.  break;   
    136.  }   
    137.  }   
    138.  else   
    139.  break;   
    140.  }   
    141.  }   
    142.  catch(IOException e){e.printStackTrace ();}   
    143.  catch(Exception e){e.printStackTrace ();}   
    144.  Utility.log(nFileLength);   
    145.  return nFileLength;   
    146.  }   
    147.  // 保存下载信息(文件指针位置)  
    148.  private void write_nPos()   
    149.  {   
    150.  try{   
    151.  output = new DataOutputStream(new FileOutputStream(tmpFile));   
    152.  output.writeInt(nStartPos.length);   
    153.  for(int i=0;i<nStartPos.length;i++)   
    154.  {   
    155.  // output.writeLong(nPos[i]);   
    156.  output.writeLong(fileSplitterFetch[i].nStartPos);   
    157.  output.writeLong(fileSplitterFetch[i].nEndPos);   
    158.  }   
    159.  output.close();   
    160.  }   
    161.  catch(IOException e){e.printStackTrace ();}   
    162.  catch(Exception e){e.printStackTrace ();}   
    163.  }   
    164.  // 读取保存的下载信息(文件指针位置)  
    165.  private void read_nPos()   
    166.  {   
    167.  try{   
    168.  DataInputStream input = new DataInputStream(new FileInputStream(tmpFile));   
    169.  int nCount = input.readInt();   
    170.  nStartPos = new long[nCount];   
    171.  nEndPos = new long[nCount];   
    172.  for(int i=0;i<nStartPos.length;i++)   
    173.  {   
    174.  nStartPos[i] = input.readLong();   
    175.  nEndPos[i] = input.readLong();   
    176.  }   
    177.  input.close();   
    178.  }   
    179.  catch(IOException e){e.printStackTrace ();}   
    180.  catch(Exception e){e.printStackTrace ();}   
    181.  }   
    182.  private void processErrorCode(int nErrorCode)   
    183.  {   
    184.  System.err.println("Error Code : " + nErrorCode);   
    185.  }   
    186.  // 停止文件下载  
    187.  public void siteStop()   
    188.  {   
    189.  bStop = true;   
    190.  for(int i=0;i<nStartPos.length;i++)   
    191.  fileSplitterFetch[i].splitterStop();   
    192.  }   
    193.  }   
    194.    

    1. /*  
    2. **FileSplitterFetch.java  
    3. */   
    4. package NetFox;   
    5. import java.io.*;   
    6. import java.net.*;   
    7. public class FileSplitterFetch extends Thread {   
    8. String sURL; //File URL   
    9. long nStartPos; //File Snippet Start Position   
    10. long nEndPos; //File Snippet End Position   
    11. int nThreadID; //Thread's ID   
    12. boolean bDownOver = false; //Downing is over   
    13. boolean bStop = false; //Stop identical   
    14. FileAccessI fileAccessI = null; //File Access interface   
    15. public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id)  
    16. throws IOException   
    17. {   
    18. this.sURL = sURL;   
    19. this.nStartPos = nStart;   
    20. this.nEndPos = nEnd;   
    21. nThreadID = id;   
    22. fileAccessI = new FileAccessI(sName,nStartPos);   
    23. }   
    24. public void run()   
    25. {   
    26. while(nStartPos < nEndPos && !bStop)   
    27. {   
    28. try{   
    29. URL url = new URL(sURL);   
    30. HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();   
    31. httpConnection.setRequestProperty("User-Agent","NetFox");   
    32. String sProperty = "bytes="+nStartPos+"-";   
    33. httpConnection.setRequestProperty("RANGE",sProperty);   
    34. Utility.log(sProperty);   
    35. InputStream input = httpConnection.getInputStream();   
    36. //logResponseHead(httpConnection);   
    37. byte[] b = new byte[1024];   
    38. int nRead;   
    39. while((nRead=input.read(b,0,1024)) > 0 && nStartPos < nEndPos   
    40. && !bStop)   
    41. {   
    42. nStartPos += fileAccessI.write(b,0,nRead);   
    43. //if(nThreadID == 1)   
    44. // Utility.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos);   
    45. }   
    46. Utility.log("Thread " + nThreadID + " is over!");   
    47. bDownOver = true;   
    48. //nPos = fileAccessI.write (b,0,nRead);   
    49. }   
    50. catch(Exception e){e.printStackTrace ();}   
    51. }   
    52. }   
    53. // 打印回应的头信息  
    54. public void logResponseHead(HttpURLConnection con)   
    55. {   
    56. for(int i=1;;i++)   
    57. {   
    58. String header=con.getHeaderFieldKey(i);   
    59. if(header!=null)   
    60. //responseHeaders.put(header,httpConnection.getHeaderField(header));   
    61. Utility.log(header+" : "+con.getHeaderField(header));   
    62. else   
    63. break;   
    64. }   
    65. }   
    66. public void splitterStop()   
    67. {   
    68. bStop = true;   
    69. }   
    70. }   
    71.   
    72. /*  
    73. **FileAccess.java  
    74. */   
    75. package NetFox;   
    76. import java.io.*;   
    77. public class FileAccessI implements Serializable{   
    78. RandomAccessFile oSavedFile;   
    79. long nPos;   
    80. public FileAccessI() throws IOException   
    81. {   
    82. this("",0);   
    83. }   
    84. public FileAccessI(String sName,long nPos) throws IOException   
    85. {   
    86. oSavedFile = new RandomAccessFile(sName,"rw");   
    87. this.nPos = nPos;   
    88. oSavedFile.seek(nPos);   
    89. }   
    90. public synchronized int write(byte[] b,int nStart,int nLen)   
    91. {   
    92. int n = -1;   
    93. try{   
    94. oSavedFile.write(b,nStart,nLen);   
    95. n = nLen;   
    96. }   
    97. catch(IOException e)   
    98. {   
    99. e.printStackTrace ();   
    100. }   
    101. return n;   
    102. }   
    103. }   
    104.   
    105. /*  
    106. **SiteInfoBean.java  
    107. */   
    108. package NetFox;   
    109. public class SiteInfoBean {   
    110. private String sSiteURL; //Site's URL   
    111. private String sFilePath; //Saved File's Path   
    112. private String sFileName; //Saved File's Name   
    113. private int nSplitter; //Count of Splited Downloading File   
    114. public SiteInfoBean()   
    115. {   
    116. //default value of nSplitter is 5   
    117. this("","","",5);   
    118. }   
    119. public SiteInfoBean(String sURL,String sPath,String sName,int nSpiltter)  
    120. {   
    121. sSiteURL= sURL;   
    122. sFilePath = sPath;   
    123. sFileName = sName;   
    124. this.nSplitter = nSpiltter;   
    125. }   
    126. public String getSSiteURL()   
    127. {   
    128. return sSiteURL;   
    129. }   
    130. public void setSSiteURL(String value)   
    131. {   
    132. sSiteURL = value;   
    133. }   
    134. public String getSFilePath()   
    135. {   
    136. return sFilePath;   
    137. }   
    138. public void setSFilePath(String value)   
    139. {   
    140. sFilePath = value;   
    141. }   
    142. public String getSFileName()   
    143. {   
    144. return sFileName;   
    145. }   
    146. public void setSFileName(String value)   
    147. {   
    148. sFileName = value;   
    149. }   
    150. public int getNSplitter()   
    151. {   
    152. return nSplitter;   
    153. }   
    154. public void setNSplitter(int nCount)   
    155. {   
    156. nSplitter = nCount;   
    157. }   
    158. }   
    159.   
    160. /*  
    161. **Utility.java  
    162. */   
    163. package NetFox;   
    164. public class Utility {   
    165. public Utility()   
    166. {   
    167. }   
    168. public static void sleep(int nSecond)   
    169. {   
    170. try{   
    171. Thread.sleep(nSecond);   
    172. }   
    173. catch(Exception e)   
    174. {   
    175. e.printStackTrace ();   
    176. }   
    177. }   
    178. public static void log(String sMsg)   
    179. {   
    180. System.err.println(sMsg);   
    181. }   
    182. public static void log(int sMsg)   
    183. {   
    184. System.err.println(sMsg);   
    185. }   
    186. }   
    187.   
    188. /*  
    189. **TestMethod.java  
    190. */   
    191. package NetFox;   
    192. public class TestMethod {   
    193. public TestMethod()   
    194. ///xx/weblogic60b2_win.exe   
    195. try{   
    196. SiteInfoBean bean = new SiteInfoBean("http://localhost/xx/weblogic60b2_win.exe",  
    197.     "L:\temp","weblogic60b2_win.exe",5);   
    198. //SiteInfoBean bean = new SiteInfoBean("http://localhost:8080/down.zip","L:\temp",  
    199.     "weblogic60b2_win.exe",5);   
    200. SiteFileFetch fileFetch = new SiteFileFetch(bean);   
    201. fileFetch.start();   
    202. }   
    203. catch(Exception e){e.printStackTrace ();}   
    204. }   
    205. public static void main(String[] args)   
    206. {   
    207. new TestMethod();   
    208. }   
    209. }  
    1. /*  
    2. **FileSplitterFetch.java  
    3. */   
    4. package NetFox;   
    5. import java.io.*;   
    6. import java.net.*;   
    7. public class FileSplitterFetch extends Thread {   
    8. String sURL; //File URL   
    9. long nStartPos; //File Snippet Start Position   
    10. long nEndPos; //File Snippet End Position   
    11. int nThreadID; //Thread's ID   
    12. boolean bDownOver = false; //Downing is over   
    13. boolean bStop = false; //Stop identical   
    14. FileAccessI fileAccessI = null; //File Access interface   
    15. public FileSplitterFetch(String sURL,String sName,long nStart,long nEnd,int id)  
    16. throws IOException   
    17. {   
    18. this.sURL = sURL;   
    19. this.nStartPos = nStart;   
    20. this.nEndPos = nEnd;   
    21. nThreadID = id;   
    22. fileAccessI = new FileAccessI(sName,nStartPos);   
    23. }   
    24. public void run()   
    25. {   
    26. while(nStartPos < nEndPos && !bStop)   
    27. {   
    28. try{   
    29. URL url = new URL(sURL);   
    30. HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection ();   
    31. httpConnection.setRequestProperty("User-Agent","NetFox");   
    32. String sProperty = "bytes="+nStartPos+"-";   
    33. httpConnection.setRequestProperty("RANGE",sProperty);   
    34. Utility.log(sProperty);   
    35. InputStream input = httpConnection.getInputStream();   
    36. //logResponseHead(httpConnection);   
    37. byte[] b = new byte[1024];   
    38. int nRead;   
    39. while((nRead=input.read(b,0,1024)) > 0 && nStartPos < nEndPos   
    40. && !bStop)   
    41. {   
    42. nStartPos += fileAccessI.write(b,0,nRead);   
    43. //if(nThreadID == 1)   
    44. // Utility.log("nStartPos = " + nStartPos + ", nEndPos = " + nEndPos);   
    45. }   
    46. Utility.log("Thread " + nThreadID + " is over!");   
    47. bDownOver = true;   
    48. //nPos = fileAccessI.write (b,0,nRead);   
    49. }   
    50. catch(Exception e){e.printStackTrace ();}   
    51. }   
    52. }   
    53. // 打印回应的头信息  
    54. public void logResponseHead(HttpURLConnection con)   
    55. {   
    56. for(int i=1;;i++)   
    57. {   
    58. String header=con.getHeaderFieldKey(i);   
    59. if(header!=null)   
    60. //responseHeaders.put(header,httpConnection.getHeaderField(header));   
    61. Utility.log(header+" : "+con.getHeaderField(header));   
    62. else   
    63. break;   
    64. }   
    65. }   
    66. public void splitterStop()   
    67. {   
    68. bStop = true;   
    69. }   
    70. }   
    71.   
    72. /*  
    73. **FileAccess.java  
    74. */   
    75. package NetFox;   
    76. import java.io.*;   
    77. public class FileAccessI implements Serializable{   
    78. RandomAccessFile oSavedFile;   
    79. long nPos;   
    80. public FileAccessI() throws IOException   
    81. {   
    82. this("",0);   
    83. }   
    84. public FileAccessI(String sName,long nPos) throws IOException   
    85. {   
    86. oSavedFile = new RandomAccessFile(sName,"rw");   
    87. this.nPos = nPos;   
    88. oSavedFile.seek(nPos);   
    89. }   
    90. public synchronized int write(byte[] b,int nStart,int nLen)   
    91. {   
    92. int n = -1;   
    93. try{   
    94. oSavedFile.write(b,nStart,nLen);   
    95. n = nLen;   
    96. }   
    97. catch(IOException e)   
    98. {   
    99. e.printStackTrace ();   
    100. }   
    101. return n;   
    102. }   
    103. }   
    104.   
    105. /*  
    106. **SiteInfoBean.java  
    107. */   
    108. package NetFox;   
    109. public class SiteInfoBean {   
    110. private String sSiteURL; //Site's URL   
    111. private String sFilePath; //Saved File's Path   
    112. private String sFileName; //Saved File's Name   
    113. private int nSplitter; //Count of Splited Downloading File   
    114. public SiteInfoBean()   
    115. {   
    116. //default value of nSplitter is 5   
    117. this("","","",5);   
    118. }   
    119. public SiteInfoBean(String sURL,String sPath,String sName,int nSpiltter)  
    120. {   
    121. sSiteURL= sURL;   
    122. sFilePath = sPath;   
    123. sFileName = sName;   
    124. this.nSplitter = nSpiltter;   
    125. }   
    126. public String getSSiteURL()   
    127. {   
    128. return sSiteURL;   
    129. }   
    130. public void setSSiteURL(String value)   
    131. {   
    132. sSiteURL = value;   
    133. }   
    134. public String getSFilePath()   
    135. {   
    136. return sFilePath;   
    137. }   
    138. public void setSFilePath(String value)   
    139. {   
    140. sFilePath = value;   
    141. }   
    142. public String getSFileName()   
    143. {   
    144. return sFileName;   
    145. }   
    146. public void setSFileName(String value)   
    147. {   
    148. sFileName = value;   
    149. }   
    150. public int getNSplitter()   
    151. {   
    152. return nSplitter;   
    153. }   
    154. public void setNSplitter(int nCount)   
    155. {   
    156. nSplitter = nCount;   
    157. }   
    158. }   
    159.   
    160. /*  
    161. **Utility.java  
    162. */   
    163. package NetFox;   
    164. public class Utility {   
    165. public Utility()   
    166. {   
    167. }   
    168. public static void sleep(int nSecond)   
    169. {   
    170. try{   
    171. Thread.sleep(nSecond);   
    172. }   
    173. catch(Exception e)   
    174. {   
    175. e.printStackTrace ();   
    176. }   
    177. }   
    178. public static void log(String sMsg)   
    179. {   
    180. System.err.println(sMsg);   
    181. }   
    182. public static void log(int sMsg)   
    183. {   
    184. System.err.println(sMsg);   
    185. }   
    186. }   
    187.   
    188. /*  
    189. **TestMethod.java  
    190. */   
    191. package NetFox;   
    192. public class TestMethod {   
    193. public TestMethod()   
    194. ///xx/weblogic60b2_win.exe   
    195. try{   
    196. SiteInfoBean bean = new SiteInfoBean("http://localhost/xx/weblogic60b2_win.exe",  
    197.     "L:\temp","weblogic60b2_win.exe",5);   
    198. //SiteInfoBean bean = new SiteInfoBean("http://localhost:8080/down.zip","L:\temp",  
    199.     "weblogic60b2_win.exe",5);   
    200. SiteFileFetch fileFetch = new SiteFileFetch(bean);   
    201. fileFetch.start();   
    202. }   
    203. catch(Exception e){e.printStackTrace ();}   
    204. }   
    205. public static void main(String[] args)   
    206. {   
    207. new TestMethod();   
    208. }   
    209. }  


    转自:http://www.ibm.com/developerworks/cn/java/joy-down/index.html

  • 相关阅读:
    [充电]多线程无锁编程--原子计数操作:__sync_fetch_and_add等12个操作
    [转]架构、框架、模式、模块、组件、插件、控件、中间件的含义
    [网络]网络爬虫
    PHP时间戳和日期转换
    两个input之间有空隙,处理方法
    去除输入框原始效果【原创】
    php做图片上传功能
    PHP获取随机数的函数rand()和mt_rand()
    PHP简单的图片上传
    基于layui的表格异步删除,ajax的简单运用
  • 原文地址:https://www.cnblogs.com/apache-x/p/5335935.html
Copyright © 2020-2023  润新知