当前位置:首页 > 谈天说地 > 正文内容

Android实现断点续传功能

34资源网2022年07月27日 11:55186

本文实例为大家分享了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加密,所以是加密之后再分片

接下来就是上传过程

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里处理上传结果,我这里有多个文件连续上传,所以结果处理看起来有点凌乱。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持萬仟网。

看完文章,还可以用支付宝扫描下面的二维码领取一个支付宝红包,目前可领1-88元不等

支付宝红包二维码

除了扫码可以领取之外,大家还可以(复制 720087999 打开✔支付宝✔去搜索, h`o`n.g.包哪里来,动动手指就能领)。

看下图所示是好多参与这次活动领取红包的朋友:

支付宝红包

扫描二维码推送至手机访问。

版权声明:本文由34楼发布,如需转载请注明出处。

本文链接:https://www.34l.com/post/19893.html

分享给朋友:

相关文章

好文分享,一辈子很短,别懂得太晚!
好文分享,一辈子很短,别懂得太晚!

曾经以为,人是慢慢长大的,后来才知道,人是一瞬间成长的;曾经也以为,人是渐渐变老的,后来才知道,人是一瞬间衰老的。人生,就像一道迷宫,上半生寻找入口,下半生寻找出口。人总是这样,经历了才能懂得,而懂得了已不再年轻。一辈子太短,懂得却太晚。一...

联合国秘书长:新冠疫苗必须要成为全球公共产品
联合国秘书长:新冠疫苗必须要成为全球公共产品

当地时间3月11日,联合国启动“必须团结一致”(Only Together)公共宣传活动,呼吁新冠疫苗能够在联合国疫苗计划主导下,成为全球公共产品,向全球各地有需要的人提供。联合国秘书长古特雷斯在致辞中表示,新冠肺炎疫情引发了全球巨大的苦难...

20句经典语录分享,​我们学会了告别,却低估了思念
20句经典语录分享,​我们学会了告别,却低估了思念

20句经典语录分享,我们学会了告别,却低估了思念,下面这些都是非常经典的语录,值得你看一下哦。1、别急,会有始料不及的运气,会有突如其来的欢喜。2、后来,你会发现这世上爱你的人有两种,一种是用满足自己的方式爱你,另一种是用满足你的方式爱你!...

古罗马大诗人贺拉斯的两句至理名言分享
古罗马大诗人贺拉斯的两句至理名言分享

1、苦难显才华,好运隐天资。2、人人皆有弱点,谁若想要寻个没有缺点的朋友,就永远找不着他所要追寻的。...

100句非常经典的人生励志语录分享
100句非常经典的人生励志语录分享

1、不要皱眉,即使在伤心的时刻,因为你从不知道有谁会醉心于你的笑容。2、失去只是一种姿势,得到并不等同于幸福。3、真理和美女都是赤裸裸的。4、我们看错了这个世界,却说世界欺骗了我们。5、我们人这一辈子不是别人的楷模,就是别人的借鉴。6、千万...

虚拟内存太低怎么设置(电脑磁盘空间不足清理步骤)
虚拟内存太低怎么设置(电脑磁盘空间不足清理步骤)

在电脑的平时使用中,经常会出现内存不足的提示,有时可能小伙伴们会疑惑了,明明自己是16G内存的性能为何也能出现这种提示呢?这是当你在运行多个大程序的时候,对内存的需求非常大,当物理内存不能满足需求时,有可能导致程序关闭而数据保存错误。那么在...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。