Android实现断点续传功能

本文实例为大家分享了android实现断点续传的具体代码 , 供大家参考 , 具体内容如下
断点续传功能 , 在文件上传中断时 , 下次上传同一文件时 , 能在上次的断点处继续上传 , 可节省时间和流量
总结规划步骤:
1.给大文件分片 , 每一个大文件发送前 , 相对应的创建一个文件夹存放所有分片
2.上传接口 , 每一个分片上传完成就删掉 , 直到所有分片上传完成 , 再删掉存放分片的文件夹 , 服务器把分片合成完整的文件 。
先看分片功能 , 传入的3个参数分别为源文件地址 , 分片大小 , 存放分片的文件夹地址 。返回的是分片个数 。
/**     *     * @param sourcefilepath    源文件地址     * @param partfilelength    分割文件的每一个片段大小标准     * @param splitpath         分割之后片段所在文件夹     * @return     * @throws exception     */    public static int splitfile(string sourcefilepath, int partfilelength, string splitpath) throws exception {        file sourcefile = null;        file targetfile = null;        inputstream ips = null;        outputstream ops = null;        outputstream configops = null;//该文件流用于存储文件分割后的相关信息 , 包括分割后的每个子文件的编号和路径,以及未分割前文件名        properties partinfo = null;//properties用于存储文件分割的信息        byte[] buffer = null;        int partnumber = 1;        sourcefile = new file(sourcefilepath);//待分割文件        ips = new fileinputstream(sourcefile);//找到读取源文件并获取输入流        //创建一个存放分片的文件夹        file tempfile = new file(splitpath);        if (!tempfile.exists()) {            tempfile.mkdirs();        }        configops = new fileoutputstream(new file(tempfile.getabsolutepath() + file.separator + "config.properties"));        buffer = new byte[partfilelength];//开辟缓存空间        int templength = 0;        partinfo = new properties();//key:1开始自动编号 value:文件路径         int slicecount = 0;        while ((templength = ips.read(buffer, 0, partfilelength)) != -1) {            string targetfilepath = tempfile.getabsolutepath() + file.separator + "part_" + (partnumber);//分割后的文件路径+文件名            slicecount = partnumber;            partinfo.setproperty((partnumber++) + "", targetfilepath);//将相关信息存储进properties            targetfile = new file(targetfilepath);            ops = new fileoutputstream(targetfile);//分割后文件            ops.write(buffer, 0, templength);//将信息写入碎片文件             ops.close();//关闭碎片文件        }        partinfo.setproperty("name", sourcefile.getname());//存储源文件名        partinfo.setproperty("slicecount", slicecount + "");//存储分片个数        partinfo.store(configops, "configfile");//将properties存储进实体文件中        ips.close();//关闭源文件流         return slicecount;    }接下来 , 和服务器协商接口 , 一共2个接口
1.uploadlargefilepre , 传入参数除了常规上传文件参数之外加了分片个数slicecount和filehashcode 。这一步是给服务器开辟存放分片的控件的 , 不执行上传操作 , 文件哈希值作为识别分片归属的唯一标准 。返回int类型rcode , 根据rcode结果判断是否执行第2步上传动作
2.uploadlargefile , 传入参数除了常规上传文件参数之外加了分片path , 分片index , isfinished 。isfinished是最后一片的依据 。客户端就在上传接口的response里继续上传下一个分片 , 直到最后一片上传完成 , 服务器才会返给这个大文件的url 。
看代码
protected void addfilemsg(string path) {        forcelogin();         if (path == null) {            return;        }        file file = new file(path);        if (file.exists()) {            immsg msg = new immsg();            msg.settype(immsg.msg_type_file);            msg.settime(system.currenttimemillis());            msg.setmsgreaded();            msg.setreceivetime(system.currenttimemillis());            accountinfo accountinfo = imapp.instance().getaccountinfo();            msg.setuserid(accountinfo.getuserid());            msg.setsex(accountinfo.getsex());            msg.setusername(accountinfo.mnickname);            msg.setheadurl(accountinfo.mhead);            msg.mmasterid = mmasterid;            msg.setmsg(new file(path).getname());            msg.setpicpath(path);            msg.setstate(immsg.state_send_uploading);            string ext = null;            if (path.endswith("doc") || path.endswith("docx")) {                ext = "doc";            } else if (path.endswith("xls") || path.endswith("xlsx")) {                ext = "xls";            } else if (path.endswith("ppt") || path.endswith("pptx")) {                ext = "ppt";            } else if (path.endswith("pdf")) {                ext = "pdf";            }            msg.setmsg_extend3(ext);             msg.mfilesize = (int) new file(path).length();            msg.sethasatt(hasatt());            addmsgtodb(msg);             isfilelistsingle = filelist.size() == 1;            sphelper sphelper = sphelper.build();            int lastslices = sphelper.get(slice_old, 0);            string aespath = sphelper.get(slice_aesencpath, "");            string lastpath = sphelper.get(slice_picpath, "");            int temptotalcount = sphelper.get(commonutils.failed_temp_send_total_count, 0);//实际发送总个数            if (lastslices == 1 && temptotalcount > 1) {                /**                 * 读取上次失败文件的进度 , 如果还剩一个失败文件 , 但是上次发送的总文件个数大于1 ,                  * 则filelist.size() == 1这个判断不能用 , 在所有判断处加一个标志                 */                isfilelistsingle = false;            }            //根据文件大小 , 判断是否用分片上传 modify hexiaokang 2019年11月5日11点01分            if (new file(path).length() < global.file_spilt_length) {//文件小于5m,常规上传方式                uploadfile(msg);            } else {                 file sourcefile = new file(path);                //分片所在文件夹,以未做aes加密的源文件名作为 分片文件夹名字                string slicedir = sourcefile.getparent() + file.separator + sourcefile.getname() + "_split";                 if (lastslices == 1                        && path.equals(lastpath)                        && new file(slicedir).exists()                        && !aespath.equals("")                        && new file(aespath).exists()) {//发送上次的旧文件中断的分片                    //只走一次                    sphelper.put(slice_old, 0);                    sliceindex = sphelper.get(slice_sliceindex, 0);                    int count = sphelper.get(slice_slicecount, 0);                    logutil2.i(tag + "&onuploadcomplete", "sendoldfiles sliceindex = " + sliceindex + ", slicecount = " + count);                    largefilepre = true;                    uploadlargefilepre(msg, count, slicedir, aespath);                } else {//发送大文件正常流程                    //给文件分片                    int partfilelength = global.file_spilt_length;//指定分割的子文件大小为5m                    //先对文件做aes加密,再进行分片,这里很重要                    string aesencpath = encryptmgr.encfile(path, accountinfo.getenctime(), accountinfo.getenckey());                    file f = new file(aesencpath);                    logutil2.i(tag + "&onuploadcomplete", "chatmsgactivity.addfilemsg: big file enc path=" + path);                     try {                        slicecount = filesliceutil.splitfile(aesencpath, partfilelength, slicedir);//将文件分割                    } catch (exception e) {                        logutil2.e(tag, "split.e:" + e.getmessage());                        e.printstacktrace();                    }//                  logutil2.e(tag+"&onuploadcomplete", "chatmsgactivity.addfilemsg: slicecount:" + slicecount);                     //分片上传                    largefilepre = false;                    uploadlargefilepre(msg, slicecount, slicedir, aesencpath);                 }            }        }    }上面这一块代码 , 除了小文件常规上传 , 就是大文件上传方式了 。大文件上传这里分了2种情况 , 
1.发送上次中断的大文件分片 , 这里就不用分片了 , 直接从sp拿到上次中断的分片count、index等信息直接上传
2.从分片到发送的全部流程 , 因为我这里对文件做了aes加密 , 所以是加密之后再分片
接下来就是上传过程
【Android实现断点续传功能】public void uploadlargefilepre(final immsg msg, final int slicecount, final string slicedir, final string aesencpath) {        if (msg.getstate() != immsg.state_send_waiting) {            msg.setstate(immsg.state_send_uploading);            mlistadapter.notifydatasetchanged();        }        accountinfo accountinfo = imapp.instance().getaccountinfo();        uploadfilehelper helper = new uploadfilehelper(accountinfo.getenctime(), accountinfo.getenckey(),                new uploadfilecallback() {                     @override                    public void onerror(call call, exception e) {                        e.printstacktrace();                        logutil2.e("onuploadcomplete", "chatmsgactivity.onerror: error(split_upload):" + e.tostring()+", call = "+call);                        failcount++;//                            if (msg.getpicpath() != null && msg.getpicpath().contains(sdcardutil.getsdcardpathex())) {//                                new file(msg.getpicpath()).delete();//                            }                        btn_other_sendfile.setclickable(true);                        commonutils.issendbtnclickable = true;                        intent comintent = new intent();                        comintent.setaction(commonutils.usbfile_complete_send);                        comintent.putextra("fail_count", failcount);                        sendbroadcast(comintent);                         tempprogress = 0;                        largefilepre = false;                        //todo 上传失败 , 上传任务终止 (需要保存失败msg的信息 , 以及分片信息)                        string picpath = msg.getpicpath();                        // 保存picpath, sliceindex, slicecount, aesencpath                        sphelper sphelper = sphelper.build();                        sphelper.put(slice_picpath, picpath);                        sphelper.put(slice_sliceindex, sliceindex);                        sphelper.put(slice_slicecount, slicecount);                        sphelper.put(slice_aesencpath, aesencpath);                        sphelper.put(slice_old, 1);//标记 , 1表示有上次失败的碎片 , 处理完上次失败的碎片之后设置为0                        return;                    }                     @override                    public void onresponse(uploadfileackpacket uploadfileackpacket) {                        logutil2.i("onuploadcomplete", "chatmsgactivity.onresponse: pre upload ack packet code="+uploadfileackpacket.getretcode()+", desc="+uploadfileackpacket.getretdesc());                        if (getmsgfromdb(msg.getid()) == null) {                            msg.setstate(immsg.state_send_failed);                            logutil2.i("onuploadcomplete", "msg not exist d = (split_upload)" + msg.getid());                            updatemsgtodb(msg);                            mlistadapter.notifydatasetchanged();                             failcount++;                            btn_other_sendfile.setclickable(true);                            commonutils.issendbtnclickable = true;                            intent comintent = new intent();                            comintent.setaction(commonutils.usbfile_complete_send);                            sendbroadcast(comintent);                             tempprogress = 0;                            return;                        }                        if (uploadfileackpacket != null && uploadfileackpacket.issuccess()) {                            logutil2.i("onuploadcomplete", "msg exist and sucess(uploadfileackpacket.sliceindex(split_upload)):" + uploadfileackpacket.sliceindex+", slicecount="+slicecount+", url="+uploadfileackpacket.murl);                            if (sliceindex < slicecount && textutils.isempty(uploadfileackpacket.murl)) {                                //更新进度条                                if (isfilelistsingle) {//单个大文件                                    int pro = 100 * sliceindex / slicecount;                                     intent uploadintent = new intent();                                    uploadintent.setaction(commonutils.usbfile_progress_send);                                    uploadintent.putextra("sentcount", -1);//-1 代表发送的是单个文件                                    uploadintent.putextra("sentpro", pro);                                    sendbroadcast(uploadintent);                                } else {//一次发送多个文件 , 包括大文件                                 }                                //删除掉上传成功的分片                                string slicepath = slicedir + file.separator + "part_" + (sliceindex);                                new file(slicepath).delete();                                sliceindex++;                                //还有待上传的分片                                uploadlargefilepre(msg, slicecount, slicedir, aesencpath);                            } else {                                //所有分片上传完成                                largefilepre = false;                                logutil2.i("onuploadcomplete", "chatmsgactivity.onresponse: 所有分片上传完成 largefilepre="+largefilepre);                                msg.updateimageuploadprogress(100);                                msg.setpicbigurl(uploadfileackpacket.murl);                                 //这里删除原文件                                 if (msg.getpicpath() != null && msg.getpicpath().contains(sdcardutil.getsdcardpathex())) {                                    file file = new file(msg.getpicpath());                                    //删除分片所在的文件夹                                    fileutil.deletefolderfile(slicedir, true);                                    //删除文件                                    file.delete();//                                    eventbus.getdefault().post(new encfileevent(encfileevent.com_file_delete, msg.getpicpath(), 0));                                    msg.setpicpath("");                                }                                if (msg.gettype() == immsg.msg_type_image) {                                    msg.setpicsmallurl(uploadfileackpacket.mthumbnail);                                    msg.mthumbwidth = this.mthumbwidth;                                    msg.mthumbheight = this.mthumbheight;                                }                                  logutil2.i("onuploadcomplete", "msg exist and sucess(msg.getpicbigurl()(split_upload)):" + msg.getpicbigurl());                                sendmsg(msg);                                sentcount++;                                sliceindex = 1;                                 if (isfilelistsingle) {//单个文件不用处理                                 } else {                                    //传递上传进度                                    intent uploadintent = new intent();                                    uploadintent.setaction(commonutils.usbfile_progress_send);                                    uploadintent.putextra("sentcount", sentcount);                                    sendbroadcast(uploadintent);                                }                                 //继续上传下一个文件                                if (sentcount < filelist.size()) {                                    addfilemsg(filelist.get(sentcount).getabsolutepath());                                } else {                                    //所有文件上传完成                                    btn_other_sendfile.setclickable(true);                                    commonutils.issendbtnclickable = true;                                    intent comintent = new intent();                                    comintent.setaction(commonutils.usbfile_complete_send);                                    sendbroadcast(comintent);                                     tempprogress = 0;                                }                            }                        } else {                            logutil2.e("onuploadcomplete", "rcode(split_upload)):" + uploadfileackpacket.getretcode()+", sliceindex="+uploadfileackpacket.sliceindex);                            if(uploadfileackpacket.getretcode()==1343688774){                                logutil2.e("onuploadcomplete", "chatmsgactivity.onresponse: 缺片了!");                            }                            msg.setstate(immsg.state_send_failed);                            updatemsgtodb(msg);                            if (!immsgmgr.notifyactivity(immsgmgr.im_cmd_imp2pmsg_ack, msg.getuserid(), msg.hasatt(), false, msg)) {                                                            }                            mlistadapter.notifydatasetchanged();                        }                    }                     @override                    public void inprogress(float progress) {                        super.inprogress(progress);//                        logutil2.i("onuploadprogress", "inprogress " + progress+", path="+msg.getpicpath()+", slicedir="+slicedir);                        logutil2.i("onuploadprogress", "chatmsgactivity.inprogress: slicecount="+slicecount+", sliceindex="+sliceindex+", sentcount="+sentcount+", list.size="+filelist.size()+", progress="+progress+", tempprogress="+tempprogress);                        int pro = (int) (progress * 100);                        if (new file(msg.getpicpath()).length() < global.file_spilt_length) {//                        }else{                            int allpro= (int)(100*(progress+(sliceindex-1))/slicecount);                            if (isfilelistsingle && allpro - tempprogress >= 1) {                                //todo 分片上传 , 进度条重新计算,                                //多个文件上传不用考虑 , 这里重新计算单个文件的上传问题                                                                logutil2.i("onuploadprogress", "chatmsgactivity.inprogress: big file allpro="+allpro);                                intent uploadintent = new intent();                                uploadintent.setaction(commonutils.usbfile_progress_send);                                uploadintent.putextra("sentcount", -1);//-1代表发送的是单个文件 , 这里是针对用户感知而言的代码逻辑                                uploadintent.putextra("sentpro", allpro);                                tempprogress = allpro;                                sendbroadcast(uploadintent);                            }                        }                        // 更新                        mlistadapter.notifydatasetchanged();                    }                }, msg);        logutil2.i("onuploadcomplete", "chatmsgactivity.uploadlargefilepre: largefilepre="+largefilepre);        if (largefilepre) {//todo 是否有过预处理            string slicepath = slicedir + file.separator + "part_" + (sliceindex);            int isfinished = sliceindex == slicecount ? 1 : 0;            helper.uploadlargefile(aesencpath, slicepath, sliceindex, isfinished);        } else {            //上传大文件 预处理            int rcode = helper.uploadlargefilepre(aesencpath, slicecount);            if (rcode == 0) {//预处理成功 , 可以执行上传任务                largefilepre = true;                string slicepath = slicedir + file.separator + "part_" + (sliceindex);                int isfinished = sliceindex == slicecount ? 1 : 0;                helper.uploadlargefile(aesencpath, slicepath, sliceindex, isfinished);            } else {                //预处理失败 , 不执行上传任务                logutil2.i("onuploadcomplete", "somewordsrcode:" + rcode+", before plus failecount="+failcount);                 msg.setstate(immsg.state_send_failed);                updatemsgtodb(msg);                mlistadapter.notifydatasetchanged();                failcount++;                btn_other_sendfile.setclickable(true);                commonutils.issendbtnclickable = true;                intent comintent = new intent();                comintent.putextra("upload_error", 0);                comintent.putextra("fail_count",failcount);                comintent.setaction(commonutils.usbfile_complete_send);                logutil.logshow("onuploadcomplete", "chatmsgactivity.uploadlargefilepre: before sendintent failcount="+failcount);                sendbroadcast(comintent);                 failcount=0;                tempprogress = 0;            }        }    }上面这一块就是上传过程
int rcode = helper.uploadlargefilepre(aesencpath, slicecount); 这一句为第一个接口预处理 , 根据结果决定是否执行上传 。
helper.uploadlargefile(aesencpath, slicepath, sliceindex, isfinished); 这一句执行上传 , 在onresponse里处理上传结果 , 我这里有多个文件连续上传 , 所以结果处理看起来有点凌乱 。
以上就是本文的全部内容 , 希望对大家的学习有所帮助 , 也希望大家多多支持www.887551.com 。
-- 展开阅读全文 --

    推荐阅读