RandomAccessFile断点续传和多线程断点续传(大文件分段下载)总结

  • 怎么断点续传?
    两点:
    1、网络数据(可以设置从文件的哪个位置下载)
    conn.setRequestProperty(“Range”, “bytes=”+startPos+”-“+endPos);
    2、写入文件(可以设置从本地文件哪个位置写入)
    使用RandomAccessFile.seek

  • 单个文件怎么分段下载?

得到文件的总长度,把长度分为N个线程进行分开下载

1、RandomAccessFile 实现断点续传:

断点 : 当前线程已经下载完成的数据长度。
续传 : 向服务器请求上次线程停止位置之后的数据。
每当线程停止时就把已下载的数据长度写入记录文件,
当重新下载时,从记录文件读取已经下载了的长度。而这个长度就是所需要的断点

续传的实现也简单,可以通过设置网络请求参数,请求服务器从指定的位置开始读取数据。
而要实现这两个功能只需要使用到httpURLconnection里面的setRequestProperty方法便可以实现

如下所示,便是向服务器请求500-1000之间的500个byte:

conn.setRequestProperty("Range", "bytes=" + 500 + "-" + 1000);

以上只是续传的一部分需求,当我们获取到下载数据时,还需要将数据写入文件,
而普通发File对象并不提供从指定位置写入数据的功能,这个时候,就需要使用到
RandomAccessFile来实现从指定位置给文件写入数据的功能

如下所示,便是从文件的的第100个byte后开始写入数据。

raFile.seek(100);

开始写入数据时还需要用到RandomAccessFile里面的另外一个方法

public void write(byte[] buffer, int byteOffset, int byteCount)

该方法的使用和OutputStream的write的使用一模一样…
以上便是断点续传的原理

具体代码:

                URL url = new URL(threadInfo.getUrl());
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(5000);
                connection.setRequestMethod("GET");

                int start = threadInfo.getStart() + threadInfo.getFinished();
                //设置范围
                connection.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd());

                //设置文件写入位置
                File file = new File(DownLoadService.DOWNLOAD_PATH, fileInfo.getFileName());
                randomAccessFile = new RandomAccessFile(file, "rwd");
                randomAccessFile.seek(start);

                //暂停之前的数据进行累加
                currentProgress += threadInfo.getFinished();

代码中重要的2个方法是

//设置开始和结束的范围,每次暂停后,从上一次的进度开始下载
connection.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd());

//从指定位置进行下载
 randomAccessFile.seek(start);

2、多线程对大文件进行分段下载:

多线程断点续传是把整个文件分割成几个部分,每个部分由一条线程执行下载,而每一条下载线程都要实现断点续传功能。
为了实现文件分割功能,我们需要使用到httpURLconnection的另外一个方法:

public int getContentLength()

当请求成功时,可以通过该方法获取到文件的总长度。 每一条线程下载大小 =
fileLength / THREAD_NUM

在多线程断点续传下载中,有一点需要特别注意: 由于文件是分成多个部分是被不
同的线程的同时下载的,这就需要,每一条线程都分别需要有一个断点记录,和一
个线程完成状态的记录;

关键代码:

    //线程数量
    private int mThreadCount = 3;
    //下载的文件的总长度
    private int length ;

        //多线程下载
        //获得每个线程下载长度
        int childLength = length / mThreadCount;
        //线程一:0,childLength 
        //线程二:childLength, childLength*2
        //线程三:childLength*2,childLength*3
        int start = childLength * i;
        int end = (i + 1) * childLength - 1;

        for (int i = 0; i < mThreadCount; i++) {
            ThreadInfo threadInfo = new ThreadInfo(i, fileInfo.getUrl(), start , end , fileInfo.getFinished());
            //最后一个除不尽的情况
            if (i == mThreadCount - 1) {
                threadInfo.setEnd(fileInfo.getLength());
            }
            //在循环中直接开启线程进行下载
            DownloadThread downloadThread = new DownloadThread(threadInfo);
            downloadThread.start();

        }



//实体类
public class ThreadInfo implements Serializable{

    public static final String THREAD_INFO = "thread_info";

    private int id;
    //下载的URL
    private String url;
    //下载开始节点
    private int start;
    //下载结束节点
    private int end;
    //当前完成进度
    private int finished;

        public ThreadInfo(int id, String url, int start, int end, int finished) {
        this.id = id;
        this.url = url;
        this.start = start;
        this.end = end;
        this.finished = finished;
    }

总结:

真正实现的时候最好使用:
1、线程池控制多个线程
2、采用同步数据库方法
3、采用Service中启动线程下载

为什么要在Service中做下载,而不在Activity中下载?

Activity是一个前台组件,可能会被关闭,也可能会被android系统回收。如果activity关闭了,在activity中创建线程就不好管理了,没法停止和其他操作。

Service属于后台组件,用户没法去关闭,优先级高,一般Android系统不会去回收的。
线程的启动关闭在Service中是比较保险的。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java多线程断点续传下载可以使用Java中的线程池和RandomAccessFile类实现。具体步骤如下: 1. 创建一个线程池,线程数量可以根据需要调整。 ``` ExecutorService executorService = Executors.newFixedThreadPool(threadCount); ``` 2. 获取文件大小和已经下载的字节数,计算出每个线程需要下载的字节数。 ``` URL url = new URL(fileUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); long fileSize = connection.getContentLength(); long threadSize = fileSize / threadCount; ``` 3. 创建一个RandomAccessFile对象,指定文件名和读写模式。 ``` RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw"); ``` 4. 为每个线程创建一个DownloadThread对象,指定线程编号、起始位置和结束位置。 ``` for (int i = 0; i < threadCount; i++) { long start = i * threadSize; long end = (i == threadCount - 1) ? fileSize - 1 : start + threadSize - 1; DownloadThread thread = new DownloadThread(fileUrl, randomAccessFile, start, end); executorService.execute(thread); } ``` 5. 在DownloadThread中使用HttpURLConnection下载文件,使用RandomAccessFile写入文件。 ``` URL url = new URL(fileUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestProperty("Range", "bytes=" + start + "-" + end); InputStream inputStream = connection.getInputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { randomAccessFile.write(buffer, 0, length); } inputStream.close(); ``` 6. 在程序关闭时,关闭RandomAccessFile和线程池。 ``` randomAccessFile.close(); executorService.shutdown(); ``` 这样就可以实现Java多线程断点续传下载了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哆啦A梦z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值