安卓 多线程下载文件

HTTP文件多线程下载

测试代码

    String downloadUrl = "http://192.168.31.162/FileServer/SoftApk/UC-11.5.5.943.apk";
    String filepath = PathUtils.getCachePath() + "UC-11.5.5.943.apk";
    /**
     * 多线程下载
     *  基于:http://blog.csdn.net/mad1989/article/details/38421465
     *
     */
    private void startMutitaskDownload(){
        DownloadTask dlTask = new DownloadTask(downloadUrl, filepath, 5, new DownloadTask.DLListener() {
            @Override
            public void onDLStart() {

            }

            @Override
            public void onDLFinished(final long costTime, final long dlSize) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        DecimalFormat dFormat   =   new   DecimalFormat("##0.00");
                        Double res = dlSize * 1.0 / 1024 / costTime;
                        String speed = dFormat.format(res);
                        tvDlAverage.setText("平均下载速度:" + speed + "Mb/s ");
                    }
                });
            }

            @Override
            public void onProgressChange(final long fileSize, final long dlSize) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvDlInfo.setText("下载速度:" + dlSize / 1024 / 1024 + "Mb/s " +
                                "下载进度:" + dlSize / (fileSize / 100) + "%");
                    }
                });
            }
        });
        dlTask.start();
    }
DownloadTask.java

import java.io.File;
import java.net.URL;
import java.net.URLConnection;
import java.util.Timer;
import java.util.TimerTask;

import utils.MLog;

/**
 * Created by e2670 on 2017/9/10.
 * FtpDownloadTask 多线程下载任务分配
 */

public class DownloadTask extends Thread{
    private String downloadUrl;
    private String filePath;
    private int threadNum;
    private long fileSize;
    private int downloadedAllSize = 0;  // 当前所有线程下载总量

    boolean isFinished = false;

    public DownloadTask(String downloadUrl, String filePath, int threadNum, DLListener dlListener) {
        this.downloadUrl = downloadUrl;
        this.threadNum = threadNum;
        this.filePath = filePath;
        this.dlListener = dlListener;
    }

    @Override
    public void run() {
        final DLThread[] threads = new DLThread[threadNum];
        try {
            URL url = new URL(downloadUrl);
            MLog.d(downloadUrl);
            URLConnection conn = url.openConnection();
            // 读取下载文件总大小
            fileSize = conn.getContentLength();
            if (fileSize == -1) { // nginx文件服务器
                fileSize = Long.valueOf(conn.getHeaderField("Content-Length"));
            }
            if (fileSize <= 0) {
                MLog.e("读取文件失败:文件大小" + fileSize);
                return;
            }
            // 计算每条线程下载的数据长度
            long blockSize = (fileSize % threadNum) == 0 ? fileSize / threadNum
                    : fileSize / threadNum + 1;
            MLog.d("threadNum:" + threadNum + "  fileSize:" + fileSize + "  blockSize:" + blockSize);

            File file = new File(filePath);
            for (int i = 0; i < threads.length; i++) {
                // 启动线程,分别下载每个线程需要下载的部分
                threads[i] = new DLThread(url, file, blockSize, (i + 1));
                threads[i].setName("FtpDLThread:" + i);
                threads[i].start();
            }
            final long startTime = System.currentTimeMillis();
            dlListener.onDLStart();
            // 每秒统计一次已下载文件大小
            final Timer timer = new Timer();
            TimerTask timerTask = new TimerTask() {
                @Override
                public void run() {
                    isFinished = true;
                    downloadedAllSize = 0;
                    for (int i = 0; i < threads.length; i++) {
                        downloadedAllSize += threads[i].getDownloadLength();
                        if (!threads[i].isCompleted()) {
                            isFinished = false;
                        }
                    }
                    dlListener.onProgressChange(fileSize, downloadedAllSize);
                    if(isFinished){
                        timer.cancel();
                        dlListener.onDLFinished(System.currentTimeMillis() - startTime,downloadedAllSize);
                    }
                }
            };
            timer.schedule(timerTask,1000,1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private DLListener dlListener;

    public interface DLListener {
        void onDLStart();

        void onDLFinished(long costTime,long dlSize);

        void onProgressChange(long fileSize, long dlSize);
    }
}

DLThread.java

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;

import utils.MLog;

/**
 * Created by e2670 on 2017/9/10.
 * FtpDLThread 完成每个独立线程的下载任务
 */
public class DLThread extends Thread {

    private static final String TAG = DLThread.class.getSimpleName();

    /**
     * 当前下载是否完成
     */
    private boolean isCompleted = false;
    /**
     * 当前下载文件长度
     */
    private long downloadLength = 0;
    /**
     * 文件保存路径
     */
    private File file;
    /**
     * 文件下载路径
     */
    private URL downloadUrl;
    /**
     * 当前下载线程ID
     */
    private int threadId;
    /**
     * 线程下载数据长度
     */
    private long blockSize;

    private int cacheSize = 100 * 1024;

    /**
     * @param downloadUrl:文件下载地址
     * @param file:文件保存路径
     * @param blockSize:下载数据长度
     * @param threadId:线程ID
     */
    public DLThread(URL downloadUrl, File file, long blockSize,
                    int threadId) {
        this.downloadUrl = downloadUrl;
        this.file = file;
        this.threadId = threadId;
        this.blockSize = blockSize;
    }

    @Override
    public void run() {
        BufferedInputStream bis = null;
        RandomAccessFile raf = null;

        try {
            URLConnection conn = downloadUrl.openConnection();
            conn.setAllowUserInteraction(true);

            long startPos = blockSize * (threadId - 1); //开始位置
            long endPos = blockSize * threadId - 1; //结束位置
            //设置当前线程下载的起点、终点
            conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
            MLog.d(Thread.currentThread().getName() + "  bytes=" + startPos + "-" + endPos);

            byte[] buffer = new byte[cacheSize];
            bis = new BufferedInputStream(conn.getInputStream());

            raf = new RandomAccessFile(file, "rwd");
            raf.seek(startPos);
            int len;
            while ((len = bis.read(buffer, 0, cacheSize)) != -1) {
                raf.write(buffer, 0, len);
                downloadLength += len;
            }
            isCompleted = true;
            MLog.d(TAG, "current thread task has finished,all size:" + downloadLength);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (raf != null) {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 线程文件是否下载完毕
     */
    public boolean isCompleted() {
        return isCompleted;
    }

    /**
     * 线程下载文件长度
     */
    public long getDownloadLength() {
        return downloadLength;
    }

}

FTP文件多线程下载

测试代码

Apache Commons Net 3.6
    String downloadUrl = "ftp://[email protected]/SoftApk/UC-11.5.5.943.apk";
    String filepath = PathUtils.getCachePath() + "UC-11.5.5.943.apk";
    /**
     * 多线程下载
     *  基于:http://blog.csdn.net/qwe511455842/article/details/76603675
     *
     */
    private void startMutitaskDownload(){
        FtpDownloadTask dlTask = new FtpDownloadTask(downloadUrl, filepath, 5, new FtpDownloadTask.DLListener() {
            @Override
            public void onDLStart() {

            }

            @Override
            public void onDLFinished(final long costTime, final long dlSize) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        DecimalFormat dFormat   =   new   DecimalFormat("##0.00");
                        Double res = dlSize * 1.0 / 1024 / costTime;
                        String speed = dFormat.format(res);
                        tvDlAverage.setText("平均下载速度:" + speed + "Mb/s ");
                    }
                });
            }

            @Override
            public void onProgressChange(final long fileSize, final long dlSize) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvDlInfo.setText("下载速度:" + dlSize / 1024 / 1024 + "Mb/s " +
                                "下载进度:" + dlSize / (fileSize / 100) + "%");
                    }
                });
            }
        });
        dlTask.start();
    }
FtpDownloadTask.java

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import utils.MLog;

/**
 * Created by e2670 on 2017/9/10.
 * FtpDownloadTask 多线程下载任务分配
 */

public class FtpDownloadTask extends Thread{
    private String downloadUrl;
    private String filePath;
    private int threadNum;
    private long fileSize;
    private int downloadedAllSize = 0;  // 当前所有线程下载总量

    boolean isFinished = false;

    public FtpDownloadTask(String downloadUrl, String filePath, int threadNum, DLListener dlListener) {
        this.downloadUrl = downloadUrl;
        this.threadNum = threadNum;
        this.filePath = filePath;
        this.dlListener = dlListener;
    }

    @Override
    public void run() {
        final FtpDLThread[] threads = new FtpDLThread[threadNum];
        try {
            MLog.d(downloadUrl);
            FTPClient client = new FTPClient();
            FtpLogin ftpLogin;
            try {
                ftpLogin = parseFtpUrl(downloadUrl);
            }catch (Exception e){
                e.printStackTrace();
                MLog.e("ftp url解析错误");
                return;
            }
            client.connect(ftpLogin.ipAddr,ftpLogin.port);
            if(ftpLogin.userName != null){
                client.login(ftpLogin.userName, ftpLogin.password);
            }

            int reply = client.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                client.disconnect();
                MLog.e("无法连接到ftp服务器,错误码为:" + reply);
                return;
            }

            String charSet = "UTF-8";
            if (!FTPReply.isPositiveCompletion(client.sendCommand("OPTS UTF8", "ON"))) {
                charSet = "GBK";
            }
            FTPFile[] files = client.listFiles(new String(ftpLogin.path.getBytes(charSet), "ISO-8859-1"));
            if(files.length > 0){
                fileSize = files[0].getSize();
            }

            if (fileSize <= 0) {
                MLog.e("读取文件失败:文件大小" + fileSize);
                return;
            }
            // 计算每条线程下载的数据长度
            long blockSize = (fileSize % threadNum) == 0 ? fileSize / threadNum
                    : fileSize / threadNum + 1;
            MLog.d("threadNum:" + threadNum + "  fileSize:" + fileSize + "  blockSize:" + blockSize);

            File file = new File(filePath);
            for (int i = 0; i < threads.length; i++) {
                // 启动线程,分别下载每个线程需要下载的部分
                threads[i] = new FtpDLThread(ftpLogin, file, blockSize, (i + 1));
                threads[i].setName("FtpDLThread:" + i);
                threads[i].start();
            }
            final long startTime = System.currentTimeMillis();
            dlListener.onDLStart();
            // 每秒统计一次已下载文件大小
            final Timer timer = new Timer();
            TimerTask timerTask = new TimerTask() {
                @Override
                public void run() {
                    isFinished = true;
                    downloadedAllSize = 0;
                    for (int i = 0; i < threads.length; i++) {
                        downloadedAllSize += threads[i].getDownloadLength();
                        if (!threads[i].isCompleted()) {
                            isFinished = false;
                        }
                    }
                    dlListener.onProgressChange(fileSize, downloadedAllSize);
                    if(isFinished){
                        timer.cancel();
                        dlListener.onDLFinished(System.currentTimeMillis() - startTime,downloadedAllSize);
                    }
                }
            };
            timer.schedule(timerTask,1000,1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * FTP url解析
     * @param fullUrl
     * @return
     */
    private FtpLogin parseFtpUrl(String fullUrl) throws Exception{
        FtpLogin ftpLogin = new FtpLogin();
        fullUrl = fullUrl.trim();
        String res;
        int beginIndex = "ftp://".length();
        int endIndex = fullUrl.indexOf(‘/‘, beginIndex);
        if(endIndex != -1){
            res =  fullUrl.substring(beginIndex, endIndex);
            String[] splitRes = res.split("@");
            if(splitRes.length > 1){    // IP+Login
                String[] splitIp = splitRes[1].split(":");
                ftpLogin.ipAddr = splitIp[0];
                if (splitIp.length > 1){
                    ftpLogin.port = Integer.parseInt(splitIp[1]);
                }else {
                    ftpLogin.port = 21;
                }
                String[] splitUser = splitRes[0].split(":");
                ftpLogin.userName = splitUser[0];
                if (splitIp.length > 1){
                    ftpLogin.password = splitUser[1];
                }else {
                    ftpLogin.password = "";
                }
            }else { // IP
                String[] splitIp = splitRes[0].split(":");
                ftpLogin.ipAddr = splitIp[0];
                if (splitIp.length > 1){
                    ftpLogin.port = Integer.parseInt(splitIp[1]);
                }else {
                    ftpLogin.port = 21;
                }
            }
            ftpLogin.path = fullUrl.substring(endIndex);
        }else {
            throw new Exception("URL解析错误");
        }
        return ftpLogin;
    }

    private DLListener dlListener;

    public interface DLListener {
        void onDLStart();

        void onDLFinished(long costTime, long dlSize);

        void onProgressChange(long fileSize, long dlSize);
    }
}

FtpDLThread.java

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

import utils.MLog;

/**
 * Created by e2670 on 2017/9/10.
 * FtpDLThread 完成每个独立线程的下载任务
 */
public class FtpDLThread extends Thread {

    private static final String TAG = FtpDLThread.class.getSimpleName();

    /**
     * 当前下载是否完成
     */
    private boolean isCompleted = false;
    /**
     * 当前下载文件长度
     */
    private long downloadLength = 0;
    /**
     * 文件保存路径
     */
    private File file;
    /**
     * 文件下载路径
     */
    private FtpLogin ftpLogin;
    /**
     * 当前下载线程ID
     */
    private int threadId;
    /**
     * 线程下载数据长度
     */
    private long blockSize;

    private int cacheSize = 100 * 1024;

    /**
     * @param ftpLogin:文件下载地址
     * @param file:文件保存路径
     * @param blockSize:下载数据长度
     * @param threadId:线程ID
     */
    public FtpDLThread(FtpLogin ftpLogin, File file, long blockSize,
                       int threadId) {
        this.ftpLogin = ftpLogin;
        this.file = file;
        this.threadId = threadId;
        this.blockSize = blockSize;
    }

    @Override
    public void run() {
        BufferedInputStream bis = null;
        RandomAccessFile raf = null;

        try {
            FTPClient client = new FTPClient();
            client.connect(ftpLogin.ipAddr, ftpLogin.port);
            if (ftpLogin.userName != null) {
                client.login(ftpLogin.userName, ftpLogin.password);
            }

            client.enterLocalPassiveMode();     //设置被动模式
            client.setFileType(FTP.BINARY_FILE_TYPE);  //设置文件传输模式
            long startPos = blockSize * (threadId - 1); //开始位置
            long endPos = blockSize * threadId - 1;     //结束位置
            client.setRestartOffset(startPos);   //设置恢复下载的位置
            MLog.d(Thread.currentThread().getName() + "  bytes=" + startPos + "-" + endPos);

            String charSet = "UTF-8";
            if (!FTPReply.isPositiveCompletion(client.sendCommand("OPTS UTF8", "ON"))) {
                charSet = "GBK";
            }
            client.allocate(cacheSize);
            InputStream is = client.retrieveFileStream(new String(ftpLogin.path.getBytes(charSet), "ISO-8859-1"));

            int reply = client.getReplyCode();
            if (!FTPReply.isPositivePreliminary(reply)) {
                client.disconnect();
                MLog.e("获取文件信息错误,错误码为:" + reply, null);
                return;
            }

            byte[] buffer = new byte[cacheSize];
            bis = new BufferedInputStream(is);

            raf = new RandomAccessFile(file, "rwd");
            raf.seek(startPos);
            int len;
            while ((len = bis.read(buffer, 0, cacheSize)) != -1) {
                raf.write(buffer, 0, len);
                downloadLength += len;
                if (downloadLength >= endPos - startPos){
                    break;
                }
            }
            isCompleted = true;
            MLog.d(TAG, "current thread task has finished,all size:" + downloadLength);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (raf != null) {
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 线程文件是否下载完毕
     */
    public boolean isCompleted() {
        return isCompleted;
    }

    /**
     * 线程下载文件长度
     */
    public long getDownloadLength() {
        return downloadLength;
    }

}

FtpLogin.java

public class FtpLogin {
    public String userName;
    public String password;
    public String ipAddr;
    public int port;
    public String path;
}

时间: 2024-10-18 04:01:19

安卓 多线程下载文件的相关文章

多线程下载文件,以及断点下载

一:前言 多线程下载文件,可能有的同学没有过多的听说过,但是断点下载肯定是听过的,也就是说像讯雷,哪怕你把电脑重启了,讯雷重新启动后也会接着原来的地方下载,那么这是怎么做到的呢? 二:代码示例 直接给出代码, 2.1.经典代码 两行经典的代码分别为: //设置下载的开始及结束位置 conn.setRequestProperty("Range", "bytes="+start+"-"+end+""); //设置读写的起点位置 R

最新---java多线程下载文件

import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class Demo { // 定义线程个数 public static int threadCount = 5; public static void main(String[] args) throws Exception { // 1,连接到服务

多线程下载文件(支持暂停、取消、断点续传)

多线程下载文件(支持暂停.取消.断点续传) 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来即可. 涉及的知识及问题 请求的数据如何分段 分段完成后如何下载和下载完成后如何组装到一起 暂停下载和继续下载的实现(wait().notifyAll().synchronized的使用) 取消下载和断点续传的实现 一.请求的数据如何分段 首先通过HttpURLConne

多线程实现多线程下载文件

下载文件的时候,一个大文件切成很多片,用多线程下载,速度会快很多 阅读代码的时候注意查看代码里面的注释想用多线程下载文件,则, 第一:得了解  RandomAccessFile  类,这是个随机访问文件类,里面可以设置 访问的 开始地址和结束地址,且该类可读可写. RandomAccessFile out = new RandomAccessFile(file, "rw"); 则表示,该类可读可写.通过 out.seek(start)  可以定位开始读取的位置. 第二:既然是网络文件下

python多线程下载文件

从文件中读取图片url和名称,将url中的文件下载下来.文件中每一行包含一个url和文件名,用制表符隔开. 1.使用requests请求url并下载文件 def download(img_url, img_name): with closing(requests.get(img_url, stream=True)) as r: with open(os.path.join(out_dir, img_name), 'wb') as f: for data in r.iter_content(102

Java多线程下载文件

package com.test.download; import java.io.File; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; /*  * 多线程下载  */ public class MulThreadDownload {     public static void main(String[]

ios开发网络学习五:MiMEType ,多线程下载文件思路,文件的压缩和解压缩

一:MiMEType:一般可以再百度上搜索到相应文件的MiMEType,或是利用c语言的api去获取文件的MiMEType : //对该文件发送一个异步请求,拿到文件的MIMEType - (void)MIMEType { //    NSString *file = @"file:///Users/文顶顶/Desktop/test.png"; [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[

AccessRandomFile多线程下载文件

写一个工具类 package com.pb.thread.demo; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; /** * 多线程复制文件工具类 * * @author denny * */ public class MutiCopyFileUtil { private String src;// 源

Android多线程下载文件

Android 实现多线程下载: 首先看下效果图: UI界面 多线程下载的时候log打印界面 开始工作,首先我们通过HttpURLConnection类连接需要下载的文件: new Thread(new Runnable() { @Override public void run() { try { url = new URL(DOWNURL); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); // conn