Java 多线程分块上传 支持断点续传

package com.test;  
  
import java.io.DataInputStream;  
import java.io.DataOutputStream;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.RandomAccessFile;  
import java.net.HttpURLConnection;  
import java.net.URL;  
/** 
 * 文件断点续传加分段上传线程 
 * @author wzztestin 
 * 
 */  
/** 
 * 文件断点续传加分段上传线程 
 * @author wzztestin 
 * 
 */  
public class DownFileFetch extends Thread {  
    DownFileInfoBean siteInfoBean = null; // 文件信息 Bean  
    long[] nStartPos; // 开始位置  
    long[] nEndPos; // 结束位置  
    DownFileSplitterFetch[] fileSplitterFetch; // 子线程对象  
    long nFileLength; // 文件长度  
    boolean bFirst = true; // 是否第一次取文件  
    boolean bStop = false; // 停止标志  
    File tmpFile; // 文件下载的临时信息  
    DataOutputStream output; // 输出到文件的输出流  
    boolean fileflag; //是本地上传还是远程下载的标志  
    File downfile; //本地文件下载  
    int splitter = 0;  
      
    /** 
     * 下载上传文件抓取初始化 
     * @param bean 
     * @throws IOException 
     */  
    public DownFileFetch(DownFileInfoBean bean) throws IOException {  
        siteInfoBean = bean;  
        /** 
         * File.separator windows是\,unix是/ 
         */  
        tmpFile = new File(bean.getSFilePath() + File.separator  
                + bean.getSFileName() + ".info");  
        if (tmpFile.exists()) {  
            bFirst = false;  
            //读取已下载的文件信息  
            read_nPos();  
        } else {  
            nStartPos = new long[bean.getNSplitter()];  
            nEndPos = new long[bean.getNSplitter()];  
        }  
        fileflag = bean.getFileflag();  
        downfile = bean.getDownfile();  
        this.splitter = bean.getNSplitter();  
    }  
  
    public void run() {  
        // 获得文件长度  
        // 分割文件  
        // 实例 FileSplitterFetch  
        // 启动 FileSplitterFetch 线程  
        // 等待子线程返回  
        try {  
            if (bFirst) {  
                nFileLength = getFileSize();  
                if (nFileLength == -1) {  
                    DownFileUtility.log("File Length is not known!");  
                } else if (nFileLength == -2) {  
                    DownFileUtility.log("File is not access!");  
                } else {  
                    for (int i = 0; i < nStartPos.length; i++) {  
                        nStartPos[i] = (long) (i * (nFileLength / nStartPos.length));  
                    }  
                    for (int i = 0; i < nEndPos.length - 1; i++) {  
                        nEndPos[i] = nStartPos[i + 1];  
                    }  
                    nEndPos[nEndPos.length - 1] = nFileLength;  
                }  
            }  
            // 启动子线程  
            fileSplitterFetch = new DownFileSplitterFetch[nStartPos.length];  
            for (int i = 0; i < nStartPos.length; i++) {  
                fileSplitterFetch[i] = new DownFileSplitterFetch(  
                        siteInfoBean.getSSiteURL(), siteInfoBean.getSFilePath()  
                                + File.separator + siteInfoBean.getSFileName()+"_"+i,  
                        nStartPos[i], nEndPos[i], i,fileflag,downfile,bFirst);  
                DownFileUtility.log("Thread " + i + " , nStartPos = " + nStartPos[i]  
                        + ", nEndPos = " + nEndPos[i]);  
                fileSplitterFetch[i].start();  
            }  
            //下载子线程是否完成标志  
            boolean breakWhile = false;  
            while (!bStop) {  
                write_nPos();  
                DownFileUtility.sleep(500);  
                breakWhile = true;  
                for (int i = 0; i < nStartPos.length; i++) {  
                    if (!fileSplitterFetch[i].bDownOver) {  
                        breakWhile = false;  
                        break;  
                    }else{  
                        write_nPos();  
                    }  
                }  
                if (breakWhile){  
                    break;  
                }  
            }  
            hebinfile(siteInfoBean.getSFilePath()+ File.separator + siteInfoBean.getSFileName(),splitter);  
            DownFileUtility.log("文件下载结束!");  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
      
    /** 
     * 获得文件长度 
     * @return 
     */  
    public long getFileSize() {  
        int nFileLength = -1;  
        if(fileflag){  
            try {  
                URL url = new URL(siteInfoBean.getSSiteURL());  
                HttpURLConnection httpConnection = (HttpURLConnection) url  
                        .openConnection();  
                httpConnection.setRequestProperty("User-Agent", "NetFox");  
                int responseCode = httpConnection.getResponseCode();  
                if (responseCode >= 400) {  
                    processErrorCode(responseCode);  
                    //represent access is error  
                    return -2;   
                }  
                String sHeader;  
                for (int i = 1;; i++) {  
                    sHeader = httpConnection.getHeaderFieldKey(i);  
                    if (sHeader != null) {  
                        if (sHeader.equals("Content-Length")) {  
                            nFileLength = Integer.parseInt(httpConnection  
                                    .getHeaderField(sHeader));  
                            break;  
                        }  
                    } else {  
                        break;  
                    }  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            DownFileUtility.log(nFileLength);  
        }else{  
            try{  
                File myflie = downfile;  
                nFileLength = (int)myflie.length();  
            }catch(Exception e){  
                e.printStackTrace();  
            }  
            DownFileUtility.log(nFileLength);  
        }  
        return nFileLength;  
    }  
  
    /** 
     * 保存下载信息(文件指针位置) 
     */  
    private void write_nPos() {  
        try {  
            output = new DataOutputStream(new FileOutputStream(tmpFile));  
            output.writeInt(nStartPos.length);  
            for (int i = 0; i < nStartPos.length; i++) {  
                output.writeLong(fileSplitterFetch[i].nStartPos);  
                output.writeLong(fileSplitterFetch[i].nEndPos);  
            }  
            output.close();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
  
    /** 
     * 读取保存的下载信息(文件指针位置) 
     */  
    private void read_nPos() {  
        try {  
            DataInputStream input = new DataInputStream(new FileInputStream(  
                    tmpFile));  
            int nCount = input.readInt();  
            nStartPos = new long[nCount];  
            nEndPos = new long[nCount];  
            for (int i = 0; i < nStartPos.length; i++) {  
                nStartPos[i] = input.readLong();  
                nEndPos[i] = input.readLong();  
            }  
            input.close();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
      
    /** 
     * 输出错误信息 
     * @param nErrorCode 
     */  
    private void processErrorCode(int nErrorCode) {  
        DownFileUtility.log("Error Code : " + nErrorCode);  
    }  
  
    /** 
     * 停止文件下载 
     */  
    public void siteStop() {  
        bStop = true;  
        for (int i = 0; i < nStartPos.length; i++)  
            fileSplitterFetch[i].splitterStop();  
    }  
      
    /** 
     * 合并文件 
     * @param sName 
     * @param splitternum 
     */  
    private void hebinfile(String sName,int splitternum){  
        try{  
            File file = new File(sName);  
            if(file.exists()){  
                file.delete();  
            }  
            RandomAccessFile saveinput = new RandomAccessFile(sName,"rw");  
            for(int i = 0;i<splitternum;i++){  
                try {  
                    RandomAccessFile input = new RandomAccessFile (new File(sName+"_"+i),"r");  
                    byte[] b = new byte[1024];  
                    int nRead;  
                    while ((nRead = input.read(b, 0, 1024)) > 0) {  
                        write(saveinput,b, 0, nRead);  
                    }  
                    input.close();  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
            DownFileUtility.log("file size is "+saveinput.length());  
        }catch(Exception e){  
            e.printStackTrace();  
        }  
    }  
      
    /** 
     * 写文件 
     * @param b 
     * @param nStart 
     * @param nLen 
     * @return 
     */  
    private int write(RandomAccessFile oSavedFile,byte[] b, int nStart, int nLen) {  
        int n = -1;  
        try {  
            oSavedFile.seek(oSavedFile.length());  
            oSavedFile.write(b, nStart, nLen);  
            n = nLen;  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        return n;  
    }  
}  






package com.test;  
  
import java.io.File;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.RandomAccessFile;  
import java.net.HttpURLConnection;  
import java.net.URL;  
/** 
 * 下载上传子线程 
 * @author wzztestin 
 * 
 */  
public class DownFileSplitterFetch extends Thread {  
    String sURL; // 下载文件的地址  
    long nStartPos; // 文件分段的开始位置  
    long nEndPos; // 文件分段的结束位置  
    int nThreadID; // 线程的 ID  
    boolean bDownOver = false; // 是否下载完成  
    boolean bStop = false; // 停止下载  
    DownFileAccess fileAccessI = null; // 文件对象  
    boolean fileflag; //是URL下载还是本地下载  
    File file = null;//本地下载文件  
    boolean bFirst = true;  
      
    /** 
     * 下载,上传子线程初始化 
     * @param sURL 
     * @param sName 
     * @param nStart 
     * @param nEnd 
     * @param id 
     * @param fileflag 
     * @param downfile 
     * @throws IOException 
     */  
    public DownFileSplitterFetch(String sURL, String sName, long nStart, long nEnd,  
            int id,boolean fileflag,File downfile,boolean bFirst) throws IOException {  
        this.sURL = sURL;  
        this.nStartPos = nStart;  
        this.nEndPos = nEnd;  
        nThreadID = id;  
        fileAccessI = new DownFileAccess(sName, nStartPos,bFirst);  
        this.fileflag = fileflag;  
        this.file = downfile;  
        this.bFirst = bFirst;  
    }  
      
    /** 
     * 线程执行 
     */  
    public void run() {  
        if(fileflag){  
            this.urldownload();  
        }else{  
            this.filedownload();  
        }  
    }  
  
    /** 
     * 打印回应的头信息 
     * @param con 
     */  
    public void logResponseHead(HttpURLConnection con) {  
        for (int i = 1;; i++) {  
            String header = con.getHeaderFieldKey(i);  
            if (header != null){  
                DownFileUtility.log(header + " : " + con.getHeaderField(header));  
            }else{  
                break;  
            }  
        }  
    }  
      
    /** 
     * 地址下载 
     */  
    private void urldownload(){  
        DownFileUtility.log("Thread " + nThreadID + " url down filesize is "+(nEndPos-nStartPos));  
        DownFileUtility.log("Thread " + nThreadID + " url start >> "+nStartPos +"------end >> "+nEndPos);  
        while (nStartPos < nEndPos && !bStop) {  
            try {  
                URL url = new URL(sURL);  
                HttpURLConnection httpConnection = (HttpURLConnection) url  
                        .openConnection();  
                httpConnection.setRequestProperty("User-Agent", "NetFox");  
                String sProperty = "bytes=" + nStartPos + "-";  
                httpConnection.setRequestProperty("RANGE", sProperty);  
                DownFileUtility.log(sProperty);  
                InputStream input = httpConnection.getInputStream();  
                byte[] b = new byte[1024];  
                int nRead;  
                while ((nRead = input.read(b, 0, 1024)) > 0  
                        && nStartPos < nEndPos && !bStop) {  
                    if((nStartPos+nRead)>nEndPos)  
                    {  
                        nRead = (int)(nEndPos - nStartPos);  
                    }  
                    nStartPos += fileAccessI.write(b, 0, nRead);  
                }  
                DownFileUtility.log("Thread " + nThreadID + " nStartPos : "+nStartPos);  
                fileAccessI.oSavedFile.close();  
                DownFileUtility.log("Thread " + nThreadID + " is over!");  
                input.close();  
                bDownOver = true;  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
        if(!bDownOver){  
            if(nStartPos >= nEndPos){  
                bDownOver = true;  
            }  
        }  
    }  
      
    /** 
     * 文件下载 
     */  
    private void filedownload(){  
        DownFileUtility.log("Thread " + nThreadID + " down filesize is "+(nEndPos-nStartPos));  
        DownFileUtility.log("Thread " + nThreadID + " start >> "+nStartPos +"------end >> "+nEndPos);  
        while (nStartPos < nEndPos && !bStop) {  
            try {  
                RandomAccessFile input = new RandomAccessFile(file,"r");  
                input.seek(nStartPos);  
                byte[] b = new byte[1024];  
                int nRead;  
                while ((nRead = input.read(b, 0, 1024)) > 0  
                        && nStartPos < nEndPos && !bStop) {  
                    if((nStartPos+nRead)>nEndPos)  
                    {  
                        nRead = (int)(nEndPos - nStartPos);  
                    }  
                    nStartPos += fileAccessI.write(b, 0, nRead);  
                }  
                fileAccessI.oSavedFile.close();  
                DownFileUtility.log("Thread " + nThreadID + " is over!");  
                input.close();  
                bDownOver = true;  
                input.close();  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
        if(!bDownOver){  
            if(nStartPos >= nEndPos){  
                bDownOver = true;  
            }  
        }  
        DownFileUtility.log("Thread " + nThreadID + "last start >> "+nStartPos );  
    }  
      
    /** 
     * 停止 
     */  
    public void splitterStop() {  
        bStop = true;  
    }  
}  





package com.test;  
  
import java.io.*;  
  
/** 
 * 文件对象 
 * @author wzztestin 
 * 
 */  
public class DownFileAccess implements Serializable {  
    /** 
     *  
     */  
    private static final long serialVersionUID = -2518013155676212866L;  
    //写入文件的流  
    RandomAccessFile oSavedFile;  
    //开始位置  
    long nPos;  
    boolean bFirst;  
  
    public DownFileAccess() throws IOException {  
        this("", 0,true);  
    }  
      
    /** 
     * 写入文件初始化 
     * @param sName 
     * @param nPos 
     * @throws IOException 
     */  
    public DownFileAccess(String sName, long nPos,boolean bFirst) throws IOException {  
        File wfile = new File(sName);  
        oSavedFile = new RandomAccessFile(wfile,"rw");  
        if(!bFirst){  
            oSavedFile.seek(wfile.length());  
        }  
        this.nPos = nPos;  
        this.bFirst = bFirst;  
    }  
      
    /** 
     * 写文件 
     * @param b 
     * @param nStart 
     * @param nLen 
     * @return 
     */  
    public synchronized int write(byte[] b, int nStart, int nLen) {  
        int n = -1;  
        try {  
            oSavedFile.write(b, nStart, nLen);  
            n = nLen;  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        return n;  
    }  
}  




package com.test;  
  
import java.io.File;  
  
public class DownFileInfoBean {  
    private String sSiteURL; // 文件的下载地址  
    private String sFilePath; // 保存文件的路径  
    private String sFileName; // 保存文件的名字  
    private int nSplitter; // 文件分成几段,默认是5段  
    private boolean fileflag; // 如果为FALSE则是本地下载,为TRUE则URL下载  
    private File downfile;  
  
    public File getDownfile() {  
        return downfile;  
    }  
  
    public void setDownfile(File downfile) {  
        this.downfile = downfile;  
    }  
  
    public boolean getFileflag() {  
        return fileflag;  
    }  
  
    public void setFileflag(boolean fileflag) {  
        this.fileflag = fileflag;  
    }  
      
    /** 
     * 默认初始化 
     */  
    public DownFileInfoBean() {  
        // default 5  
        this("", "", "", 5,false,null);  
    }  
      
    /** 
     * 下载文件信息初始化 
     * @param sURL 下载的链接地址 
     * @param sPath 上传的保存路径 
     * @param sName 上传保存的文件名 
     * @param nSpiltter 文件分段个数 
     * @param fileflag 是本地文件上传下载还是链接上传下载的标志 
     * @param downfile 本地下载文件(FILE) 
     */  
    public DownFileInfoBean(String sURL, String sPath, String sName, int nSpiltter,boolean fileflag,File downfile) {  
        sSiteURL = sURL;  
        sFilePath = sPath;  
        sFileName = sName;  
        this.nSplitter = nSpiltter;  
        this.fileflag = fileflag;  
        this.downfile = downfile;  
    }  
  
    public String getSSiteURL() {  
        return sSiteURL;  
    }  
  
    public void setSSiteURL(String value) {  
        sSiteURL = value;  
    }  
  
    public String getSFilePath() {  
        return sFilePath;  
    }  
  
    public void setSFilePath(String value) {  
        sFilePath = value;  
    }  
  
    public String getSFileName() {  
        return sFileName;  
    }  
  
    public void setSFileName(String value) {  
        sFileName = value;  
    }  
  
    public int getNSplitter() {  
        return nSplitter;  
    }  
  
    public void setNSplitter(int nCount) {  
        nSplitter = nCount;  
    }  
}  





package com.test;  
  
/** 
 * 简单的工具类 
 * @author wzztestin 
 * 
 */  
public class DownFileUtility {  
    public DownFileUtility() {  
    }  
      
    /** 
     * 休眠时长 
     * @param nSecond 
     */  
    public static void sleep(int nSecond) {  
        try {  
            Thread.sleep(nSecond);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
      
    /** 
     * 打印日志信息 
     * @param sMsg 
     */  
    public static void log(String sMsg) {  
        System.err.println(sMsg);  
    }  
      
    /** 
     * 打印日志信息 
     * @param sMsg 
     */  
    public static void log(int sMsg) {  
        System.err.println(sMsg);  
    }  
}  




package com.test;  
  
public class TestMethod {  
    public TestMethod() {  
        try {  
            DownFileInfoBean bean = new DownFileInfoBean(  
                    "http://cdn.market.hiapk.com/data/upload//2012/09_27/17/car.wu.wei.kyo.shandian_174928.apk", "D:\\temp",  
                    "shandian_174928.apk", 5,true,null);  
            /*File file = new File("D:\\dan07.apk"); 
            DownFileInfoBean bean = new DownFileInfoBean(null, "D:\\temp", 
                    "dan07.apk", 3,false,file);*/  
            DownFileFetch fileFetch = new DownFileFetch(bean);  
            fileFetch.start();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
  
    public static void main(String[] args) {  
        new TestMethod();  
    }  
}  

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。