java多线程分块上传并支持断点续传最新修正完整版本

  1. package com.test;  
  2.   
  3. import java.io.DataInputStream;  
  4. import java.io.DataOutputStream;  
  5. import java.io.File;  
  6. import java.io.FileInputStream;  
  7. import java.io.FileOutputStream;  
  8. import java.io.IOException;  
  9. import java.io.RandomAccessFile;  
  10. import java.net.HttpURLConnection;  
  11. import java.net.URL;  
  12. /** 
  13.  * 文件断点续传加分段上传线程 
  14.  * @author wzztestin 
  15.  * 
  16.  */  
  17. /** 
  18.  * 文件断点续传加分段上传线程 
  19.  * @author wzztestin 
  20.  * 
  21.  */  
  22. public class DownFileFetch extends Thread {  
  23.     DownFileInfoBean siteInfoBean = null// 文件信息 Bean  
  24.     long[] nStartPos; // 开始位置  
  25.     long[] nEndPos; // 结束位置  
  26.     DownFileSplitterFetch[] fileSplitterFetch; // 子线程对象  
  27.     long nFileLength; // 文件长度  
  28.     boolean bFirst = true// 是否第一次取文件  
  29.     boolean bStop = false// 停止标志  
  30.     File tmpFile; // 文件下载的临时信息  
  31.     DataOutputStream output; // 输出到文件的输出流  
  32.     boolean fileflag; //是本地上传还是远程下载的标志  
  33.     File downfile; //本地文件下载  
  34.     int splitter = 0;  
  35.       
  36.     /** 
  37.      * 下载上传文件抓取初始化 
  38.      * @param bean 
  39.      * @throws IOException 
  40.      */  
  41.     public DownFileFetch(DownFileInfoBean bean) throws IOException {  
  42.         siteInfoBean = bean;  
  43.         /** 
  44.          * File.separator windows是\,unix是/ 
  45.          */  
  46.         tmpFile = new File(bean.getSFilePath() + File.separator  
  47.                 + bean.getSFileName() + ".info");  
  48.         if (tmpFile.exists()) {  
  49.             bFirst = false;  
  50.             //读取已下载的文件信息  
  51.             read_nPos();  
  52.         } else {  
  53.             nStartPos = new long[bean.getNSplitter()];  
  54.             nEndPos = new long[bean.getNSplitter()];  
  55.         }  
  56.         fileflag = bean.getFileflag();  
  57.         downfile = bean.getDownfile();  
  58.         this.splitter = bean.getNSplitter();  
  59.     }  
  60.   
  61.     public void run() {  
  62.         // 获得文件长度  
  63.         // 分割文件  
  64.         // 实例 FileSplitterFetch  
  65.         // 启动 FileSplitterFetch 线程  
  66.         // 等待子线程返回  
  67.         try {  
  68.             if (bFirst) {  
  69.                 nFileLength = getFileSize();  
  70.                 if (nFileLength == -1) {  
  71.                     DownFileUtility.log("File Length is not known!");  
  72.                 } else if (nFileLength == -2) {  
  73.                     DownFileUtility.log("File is not access!");  
  74.                 } else {  
  75.                     for (int i = 0; i < nStartPos.length; i++) {  
  76.                         nStartPos[i] = (long) (i * (nFileLength / nStartPos.length));  
  77.                     }  
  78.                     for (int i = 0; i < nEndPos.length - 1; i++) {  
  79.                         nEndPos[i] = nStartPos[i + 1];  
  80.                     }  
  81.                     nEndPos[nEndPos.length - 1] = nFileLength;  
  82.                 }  
  83.             }  
  84.             // 启动子线程  
  85.             fileSplitterFetch = new DownFileSplitterFetch[nStartPos.length];  
  86.             for (int i = 0; i < nStartPos.length; i++) {  
  87.                 fileSplitterFetch[i] = new DownFileSplitterFetch(  
  88.                         siteInfoBean.getSSiteURL(), siteInfoBean.getSFilePath()  
  89.                                 + File.separator + siteInfoBean.getSFileName()+"_"+i,  
  90.                         nStartPos[i], nEndPos[i], i,fileflag,downfile,bFirst);  
  91.                 DownFileUtility.log("Thread " + i + " , nStartPos = " + nStartPos[i]  
  92.                         + ", nEndPos = " + nEndPos[i]);  
  93.                 fileSplitterFetch[i].start();  
  94.             }  
  95.             //下载子线程是否完成标志  
  96.             boolean breakWhile = false;  
  97.             while (!bStop) {  
  98.                 write_nPos();  
  99.                 DownFileUtility.sleep(500);  
  100.                 breakWhile = true;  
  101.                 for (int i = 0; i < nStartPos.length; i++) {  
  102.                     if (!fileSplitterFetch[i].bDownOver) {  
  103.                         breakWhile = false;  
  104.                         break;  
  105.                     }else{  
  106.                         write_nPos();  
  107.                     }  
  108.                 }  
  109.                 if (breakWhile){  
  110.                     break;  
  111.                 }  
  112.             }  
  113.             hebinfile(siteInfoBean.getSFilePath()+ File.separator + siteInfoBean.getSFileName(),splitter);  
  114.             DownFileUtility.log("文件下载结束!");  
  115.         } catch (Exception e) {  
  116.             e.printStackTrace();  
  117.         }  
  118.     }  
  119.       
  120.     /** 
  121.      * 获得文件长度 
  122.      * @return 
  123.      */  
  124.     public long getFileSize() {  
  125.         int nFileLength = -1;  
  126.         if(fileflag){  
  127.             try {  
  128.                 URL url = new URL(siteInfoBean.getSSiteURL());  
  129.                 HttpURLConnection httpConnection = (HttpURLConnection) url  
  130.                         .openConnection();  
  131.                 httpConnection.setRequestProperty("User-Agent""NetFox");  
  132.                 int responseCode = httpConnection.getResponseCode();  
  133.                 if (responseCode >= 400) {  
  134.                     processErrorCode(responseCode);  
  135.                     //represent access is error  
  136.                     return -2;   
  137.                 }  
  138.                 String sHeader;  
  139.                 for (int i = 1;; i++) {  
  140.                     sHeader = httpConnection.getHeaderFieldKey(i);  
  141.                     if (sHeader != null) {  
  142.                         if (sHeader.equals("Content-Length")) {  
  143.                             nFileLength = Integer.parseInt(httpConnection  
  144.                                     .getHeaderField(sHeader));  
  145.                             break;  
  146.                         }  
  147.                     } else {  
  148.                         break;  
  149.                     }  
  150.                 }  
  151.             } catch (IOException e) {  
  152.                 e.printStackTrace();  
  153.             } catch (Exception e) {  
  154.                 e.printStackTrace();  
  155.             }  
  156.             DownFileUtility.log(nFileLength);  
  157.         }else{  
  158.             try{  
  159.                 File myflie = downfile;  
  160.                 nFileLength = (int)myflie.length();  
  161.             }catch(Exception e){  
  162.                 e.printStackTrace();  
  163.             }  
  164.             DownFileUtility.log(nFileLength);  
  165.         }  
  166.         return nFileLength;  
  167.     }  
  168.   
  169.     /** 
  170.      * 保存下载信息(文件指针位置) 
  171.      */  
  172.     private void write_nPos() {  
  173.         try {  
  174.             output = new DataOutputStream(new FileOutputStream(tmpFile));  
  175.             output.writeInt(nStartPos.length);  
  176.             for (int i = 0; i < nStartPos.length; i++) {  
  177.                 output.writeLong(fileSplitterFetch[i].nStartPos);  
  178.                 output.writeLong(fileSplitterFetch[i].nEndPos);  
  179.             }  
  180.             output.close();  
  181.         } catch (IOException e) {  
  182.             e.printStackTrace();  
  183.         } catch (Exception e) {  
  184.             e.printStackTrace();  
  185.         }  
  186.     }  
  187.   
  188.     /** 
  189.      * 读取保存的下载信息(文件指针位置) 
  190.      */  
  191.     private void read_nPos() {  
  192.         try {  
  193.             DataInputStream input = new DataInputStream(new FileInputStream(  
  194.                     tmpFile));  
  195.             int nCount = input.readInt();  
  196.             nStartPos = new long[nCount];  
  197.             nEndPos = new long[nCount];  
  198.             for (int i = 0; i < nStartPos.length; i++) {  
  199.                 nStartPos[i] = input.readLong();  
  200.                 nEndPos[i] = input.readLong();  
  201.             }  
  202.             input.close();  
  203.         } catch (IOException e) {  
  204.             e.printStackTrace();  
  205.         } catch (Exception e) {  
  206.             e.printStackTrace();  
  207.         }  
  208.     }  
  209.       
  210.     /** 
  211.      * 输出错误信息 
  212.      * @param nErrorCode 
  213.      */  
  214.     private void processErrorCode(int nErrorCode) {  
  215.         DownFileUtility.log("Error Code : " + nErrorCode);  
  216.     }  
  217.   
  218.     /** 
  219.      * 停止文件下载 
  220.      */  
  221.     public void siteStop() {  
  222.         bStop = true;  
  223.         for (int i = 0; i < nStartPos.length; i++)  
  224.             fileSplitterFetch[i].splitterStop();  
  225.     }  
  226.       
  227.     /** 
  228.      * 合并文件 
  229.      * @param sName 
  230.      * @param splitternum 
  231.      */  
  232.     private void hebinfile(String sName,int splitternum){  
  233.         try{  
  234.             File file = new File(sName);  
  235.             if(file.exists()){  
  236.                 file.delete();  
  237.             }  
  238.             RandomAccessFile saveinput = new RandomAccessFile(sName,"rw");  
  239.             for(int i = 0;i<splitternum;i++){  
  240.                 try {  
  241.                     RandomAccessFile input = new RandomAccessFile (new File(sName+"_"+i),"r");  
  242.                     byte[] b = new byte[1024];  
  243.                     int nRead;  
  244.                     while ((nRead = input.read(b, 01024)) > 0) {  
  245.                         write(saveinput,b, 0, nRead);  
  246.                     }  
  247.                     input.close();  
  248.                 } catch (Exception e) {  
  249.                     e.printStackTrace();  
  250.                 }  
  251.             }  
  252.             DownFileUtility.log("file size is "+saveinput.length());  
  253.         }catch(Exception e){  
  254.             e.printStackTrace();  
  255.         }  
  256.     }  
  257.       
  258.     /** 
  259.      * 写文件 
  260.      * @param b 
  261.      * @param nStart 
  262.      * @param nLen 
  263.      * @return 
  264.      */  
  265.     private int write(RandomAccessFile oSavedFile,byte[] b, int nStart, int nLen) {  
  266.         int n = -1;  
  267.         try {  
  268.             oSavedFile.seek(oSavedFile.length());  
  269.             oSavedFile.write(b, nStart, nLen);  
  270.             n = nLen;  
  271.         } catch (IOException e) {  
  272.             e.printStackTrace();  
  273.         }  
  274.         return n;  
  275.     }  
  276. }  

 

Java代码   收藏代码
  1. package com.test;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.RandomAccessFile;  
  7. import java.net.HttpURLConnection;  
  8. import java.net.URL;  
  9. /** 
  10.  * 下载上传子线程 
  11.  * @author wzztestin 
  12.  * 
  13.  */  
  14. public class DownFileSplitterFetch extends Thread {  
  15.     String sURL; // 下载文件的地址  
  16.     long nStartPos; // 文件分段的开始位置  
  17.     long nEndPos; // 文件分段的结束位置  
  18.     int nThreadID; // 线程的 ID  
  19.     boolean bDownOver = false// 是否下载完成  
  20.     boolean bStop = false// 停止下载  
  21.     DownFileAccess fileAccessI = null// 文件对象  
  22.     boolean fileflag; //是URL下载还是本地下载  
  23.     File file = null;//本地下载文件  
  24.     boolean bFirst = true;  
  25.       
  26.     /** 
  27.      * 下载,上传子线程初始化 
  28.      * @param sURL 
  29.      * @param sName 
  30.      * @param nStart 
  31.      * @param nEnd 
  32.      * @param id 
  33.      * @param fileflag 
  34.      * @param downfile 
  35.      * @throws IOException 
  36.      */  
  37.     public DownFileSplitterFetch(String sURL, String sName, long nStart, long nEnd,  
  38.             int id,boolean fileflag,File downfile,boolean bFirst) throws IOException {  
  39.         this.sURL = sURL;  
  40.         this.nStartPos = nStart;  
  41.         this.nEndPos = nEnd;  
  42.         nThreadID = id;  
  43.         fileAccessI = new DownFileAccess(sName, nStartPos,bFirst);  
  44.         this.fileflag = fileflag;  
  45.         this.file = downfile;  
  46.         this.bFirst = bFirst;  
  47.     }  
  48.       
  49.     /** 
  50.      * 线程执行 
  51.      */  
  52.     public void run() {  
  53.         if(fileflag){  
  54.             this.urldownload();  
  55.         }else{  
  56.             this.filedownload();  
  57.         }  
  58.     }  
  59.   
  60.     /** 
  61.      * 打印回应的头信息 
  62.      * @param con 
  63.      */  
  64.     public void logResponseHead(HttpURLConnection con) {  
  65.         for (int i = 1;; i++) {  
  66.             String header = con.getHeaderFieldKey(i);  
  67.             if (header != null){  
  68.                 DownFileUtility.log(header + " : " + con.getHeaderField(header));  
  69.             }else{  
  70.                 break;  
  71.             }  
  72.         }  
  73.     }  
  74.       
  75.     /** 
  76.      * 地址下载 
  77.      */  
  78.     private void urldownload(){  
  79.         DownFileUtility.log("Thread " + nThreadID + " url down filesize is "+(nEndPos-nStartPos));  
  80.         DownFileUtility.log("Thread " + nThreadID + " url start >> "+nStartPos +"------end >> "+nEndPos);  
  81.         while (nStartPos < nEndPos && !bStop) {  
  82.             try {  
  83.                 URL url = new URL(sURL);  
  84.                 HttpURLConnection httpConnection = (HttpURLConnection) url  
  85.                         .openConnection();  
  86.                 httpConnection.setRequestProperty("User-Agent""NetFox");  
  87.                 String sProperty = "bytes=" + nStartPos + "-";  
  88.                 httpConnection.setRequestProperty("RANGE", sProperty);  
  89.                 DownFileUtility.log(sProperty);  
  90.                 InputStream input = httpConnection.getInputStream();  
  91.                 byte[] b = new byte[1024];  
  92.                 int nRead;  
  93.                 while ((nRead = input.read(b, 01024)) > 0  
  94.                         && nStartPos < nEndPos && !bStop) {  
  95.                     if((nStartPos+nRead)>nEndPos)  
  96.                     {  
  97.                         nRead = (int)(nEndPos - nStartPos);  
  98.                     }  
  99.                     nStartPos += fileAccessI.write(b, 0, nRead);  
  100.                 }  
  101.                 DownFileUtility.log("Thread " + nThreadID + " nStartPos : "+nStartPos);  
  102.                 fileAccessI.oSavedFile.close();  
  103.                 DownFileUtility.log("Thread " + nThreadID + " is over!");  
  104.                 input.close();  
  105.                 bDownOver = true;  
  106.             } catch (Exception e) {  
  107.                 e.printStackTrace();  
  108.             }  
  109.         }  
  110.         if(!bDownOver){  
  111.             if(nStartPos >= nEndPos){  
  112.                 bDownOver = true;  
  113.             }  
  114.         }  
  115.     }  
  116.       
  117.     /** 
  118.      * 文件下载 
  119.      */  
  120.     private void filedownload(){  
  121.         DownFileUtility.log("Thread " + nThreadID + " down filesize is "+(nEndPos-nStartPos));  
  122.         DownFileUtility.log("Thread " + nThreadID + " start >> "+nStartPos +"------end >> "+nEndPos);  
  123.         while (nStartPos < nEndPos && !bStop) {  
  124.             try {  
  125.                 RandomAccessFile input = new RandomAccessFile(file,"r");  
  126.                 input.seek(nStartPos);  
  127.                 byte[] b = new byte[1024];  
  128.                 int nRead;  
  129.                 while ((nRead = input.read(b, 01024)) > 0  
  130.                         && nStartPos < nEndPos && !bStop) {  
  131.                     if((nStartPos+nRead)>nEndPos)  
  132.                     {  
  133.                         nRead = (int)(nEndPos - nStartPos);  
  134.                     }  
  135.                     nStartPos += fileAccessI.write(b, 0, nRead);  
  136.                 }  
  137.                 fileAccessI.oSavedFile.close();  
  138.                 DownFileUtility.log("Thread " + nThreadID + " is over!");  
  139.                 input.close();  
  140.                 bDownOver = true;  
  141.                 input.close();  
  142.             } catch (Exception e) {  
  143.                 e.printStackTrace();  
  144.             }  
  145.         }  
  146.         if(!bDownOver){  
  147.             if(nStartPos >= nEndPos){  
  148.                 bDownOver = true;  
  149.             }  
  150.         }  
  151.         DownFileUtility.log("Thread " + nThreadID + "last start >> "+nStartPos );  
  152.     }  
  153.       
  154.     /** 
  155.      * 停止 
  156.      */  
  157.     public void splitterStop() {  
  158.         bStop = true;  
  159.     }  
  160. }  

 

Java代码   收藏代码
  1. package com.test;  
  2.   
  3. import java.io.*;  
  4.   
  5. /** 
  6.  * 文件对象 
  7.  * @author wzztestin 
  8.  * 
  9.  */  
  10. public class DownFileAccess implements Serializable {  
  11.     /** 
  12.      *  
  13.      */  
  14.     private static final long serialVersionUID = -2518013155676212866L;  
  15.     //写入文件的流  
  16.     RandomAccessFile oSavedFile;  
  17.     //开始位置  
  18.     long nPos;  
  19.     boolean bFirst;  
  20.   
  21.     public DownFileAccess() throws IOException {  
  22.         this(""0,true);  
  23.     }  
  24.       
  25.     /** 
  26.      * 写入文件初始化 
  27.      * @param sName 
  28.      * @param nPos 
  29.      * @throws IOException 
  30.      */  
  31.     public DownFileAccess(String sName, long nPos,boolean bFirst) throws IOException {  
  32.         File wfile = new File(sName);  
  33.         oSavedFile = new RandomAccessFile(wfile,"rw");  
  34.         if(!bFirst){  
  35.             oSavedFile.seek(wfile.length());  
  36.         }  
  37.         this.nPos = nPos;  
  38.         this.bFirst = bFirst;  
  39.     }  
  40.       
  41.     /** 
  42.      * 写文件 
  43.      * @param b 
  44.      * @param nStart 
  45.      * @param nLen 
  46.      * @return 
  47.      */  
  48.     public synchronized int write(byte[] b, int nStart, int nLen) {  
  49.         int n = -1;  
  50.         try {  
  51.             oSavedFile.write(b, nStart, nLen);  
  52.             n = nLen;  
  53.         } catch (IOException e) {  
  54.             e.printStackTrace();  
  55.         }  
  56.         return n;  
  57.     }  
  58. }  

 

Java代码   收藏代码
  1. package com.test;  
  2.   
  3. import java.io.File;  
  4.   
  5. public class DownFileInfoBean {  
  6.     private String sSiteURL; // 文件的下载地址  
  7.     private String sFilePath; // 保存文件的路径  
  8.     private String sFileName; // 保存文件的名字  
  9.     private int nSplitter; // 文件分成几段,默认是5段  
  10.     private boolean fileflag; // 如果为FALSE则是本地下载,为TRUE则URL下载  
  11.     private File downfile;  
  12.   
  13.     public File getDownfile() {  
  14.         return downfile;  
  15.     }  
  16.   
  17.     public void setDownfile(File downfile) {  
  18.         this.downfile = downfile;  
  19.     }  
  20.   
  21.     public boolean getFileflag() {  
  22.         return fileflag;  
  23.     }  
  24.   
  25.     public void setFileflag(boolean fileflag) {  
  26.         this.fileflag = fileflag;  
  27.     }  
  28.       
  29.     /** 
  30.      * 默认初始化 
  31.      */  
  32.     public DownFileInfoBean() {  
  33.         // default 5  
  34.         this(""""""5,false,null);  
  35.     }  
  36.       
  37.     /** 
  38.      * 下载文件信息初始化 
  39.      * @param sURL 下载的链接地址 
  40.      * @param sPath 上传的保存路径 
  41.      * @param sName 上传保存的文件名 
  42.      * @param nSpiltter 文件分段个数 
  43.      * @param fileflag 是本地文件上传下载还是链接上传下载的标志 
  44.      * @param downfile 本地下载文件(FILE) 
  45.      */  
  46.     public DownFileInfoBean(String sURL, String sPath, String sName, int nSpiltter,boolean fileflag,File downfile) {  
  47.         sSiteURL = sURL;  
  48.         sFilePath = sPath;  
  49.         sFileName = sName;  
  50.         this.nSplitter = nSpiltter;  
  51.         this.fileflag = fileflag;  
  52.         this.downfile = downfile;  
  53.     }  
  54.   
  55.     public String getSSiteURL() {  
  56.         return sSiteURL;  
  57.     }  
  58.   
  59.     public void setSSiteURL(String value) {  
  60.         sSiteURL = value;  
  61.     }  
  62.   
  63.     public String getSFilePath() {  
  64.         return sFilePath;  
  65.     }  
  66.   
  67.     public void setSFilePath(String value) {  
  68.         sFilePath = value;  
  69.     }  
  70.   
  71.     public String getSFileName() {  
  72.         return sFileName;  
  73.     }  
  74.   
  75.     public void setSFileName(String value) {  
  76.         sFileName = value;  
  77.     }  
  78.   
  79.     public int getNSplitter() {  
  80.         return nSplitter;  
  81.     }  
  82.   
  83.     public void setNSplitter(int nCount) {  
  84.         nSplitter = nCount;  
  85.     }  
  86. }  

 

Java代码   收藏代码
  1. package com.test;  
  2.   
  3. /** 
  4.  * 简单的工具类 
  5.  * @author wzztestin 
  6.  * 
  7.  */  
  8. public class DownFileUtility {  
  9.     public DownFileUtility() {  
  10.     }  
  11.       
  12.     /** 
  13.      * 休眠时长 
  14.      * @param nSecond 
  15.      */  
  16.     public static void sleep(int nSecond) {  
  17.         try {  
  18.             Thread.sleep(nSecond);  
  19.         } catch (Exception e) {  
  20.             e.printStackTrace();  
  21.         }  
  22.     }  
  23.       
  24.     /** 
  25.      * 打印日志信息 
  26.      * @param sMsg 
  27.      */  
  28.     public static void log(String sMsg) {  
  29.         System.err.println(sMsg);  
  30.     }  
  31.       
  32.     /** 
  33.      * 打印日志信息 
  34.      * @param sMsg 
  35.      */  
  36.     public static void log(int sMsg) {  
  37.         System.err.println(sMsg);  
  38.     }  
  39. }  

 

Java代码   收藏代码
  1. package com.test;  
  2.   
  3. public class TestMethod {  
  4.     public TestMethod() {  
  5.         try {  
  6.             DownFileInfoBean bean = new DownFileInfoBean(  
  7.                     "http://cdn.market.hiapk.com/data/upload//2012/09_27/17/car.wu.wei.kyo.shandian_174928.apk""D:\\temp",  
  8.                     "shandian_174928.apk"5,true,null);  
  9.             /*File file = new File("D:\\dan07.apk"); 
  10.             DownFileInfoBean bean = new DownFileInfoBean(null, "D:\\temp", 
  11.                     "dan07.apk", 3,false,file);*/  
  12.             DownFileFetch fileFetch = new DownFileFetch(bean);  
  13.             fileFetch.start();  
  14.         } catch (Exception e) {  
  15.             e.printStackTrace();  
  16.         }  
  17.     }  
  18.   
  19.     public static void main(String[] args) {  
  20.         new TestMethod();  
  21.     }  
  22. }  
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值