zoukankan      html  css  js  c++  java
  • web大文件下载+断点续传

    实现原理
    (1)首先获得下载文件的长度,然后设置本地文件的长度。
    (2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。
    如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示:
    ?例如10M大小,使用3个线程来下载,
    线程下载的数据长度 ? (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M
    下载开始位置:线程id*每条线程下载的数据长度 = ?
    下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?

    Activity代码

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        @SuppressLint("HandlerLeak")
        public static Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                int size = msg.getData().getInt("size");
    //            progressbar.setProgress();
                float temp = (float) size / (float)progressbar.getMax();
                int progress = (int) (temp * 100);
                if (progress == 100) {
                    Log.e("TAG", "handleMessage: " + "下载完成");
                }
                tv_result.setText("下载进度:" + progress + "%");
            }
        };
        private EditText ed;
        private Button btn_download;
        private static ProgressBar progressbar;
        private static TextView tv_result;
        private String urlstring;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
     
        private void initView() {
            ed = (EditText) findViewById(R.id.ed);
            btn_download = (Button) findViewById(R.id.btn_download);
            progressbar = (ProgressBar) findViewById(R.id.progressbar);
            tv_result = (TextView) findViewById(R.id.tv_result);
     
     
            btn_download.setOnClickListener(this);
        }
     
     
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_download:
                    submit();
                    download();
                    break;
            }
        }
     
        //下载文件
        private void download() {
    //获取sd卡路径
            String path = Environment.getExternalStorageDirectory() + "/morethreaddownload/";
            File file = new File(path);
            if (!file.exists()) {
    //            如果文件目录不存在,就创建此文件夹
                file.mkdir();
            }
     
     
    //      指定下载的大文件的名称
            String filename = "fulin.apk";
    //        要下载的文件路径
            String filepath = path + filename;
    //        线程的数量
            int threadcount = 5;
     
     
    //  开启子线程下载文件(获取文件的长度)
            DownLoadTask task = new DownLoadTask(progressbar,urlstring,filepath,threadcount);
            task.start();
        }
        private void submit() {
    //输入框中用户输入的网络路径
            urlstring = ed.getText().toString().trim();
            if (TextUtils.isEmpty(urlstring)) {
                Toast.makeText(this, "edString不能为空", Toast.LENGTH_SHORT).show();
                return;
            }
        }
     
    }
    DownLoadTask类

    public class DownLoadTask extends Thread {
        //     网路文件的下载地址
        private String downloadUrl;
        //    保存文件的路径
        private String filePath;
        //    线程的数量
        private int threadcount;
    //    进度条
        private ProgressBar  progressBar;
    //    文件的大小
        public static int filesize;
        //    每个线程的下载量
        private int blockSize;
    //构造方法
        public DownLoadTask(ProgressBar  progressBar, String downloadUrl, String filePath, int threadcount) {
            this.progressBar=progressBar;
            this.downloadUrl = downloadUrl;
            this.filePath = filePath;
            this.threadcount = threadcount;
        }
     
        @Override
        public void run() {
            super.run();
    //        线程数组
            FileDownloadThread[] threads = new FileDownloadThread[threadcount];
            try {
                URL url = new URL(downloadUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.connect();
                if (conn.getResponseCode() == 200) {
    //                读取下载文件的总长度
                    filesize = conn.getContentLength();
                    if (filesize <= 0) {
                        Log.e(TAG, "run: " + "读取文件失败");
                        return;
                    }
     
    //                设置progressbar的最大值
                    progressBar.setMax(filesize);
    //
    //              计算每条线程下载的数据长度
                    blockSize = filesize % threadcount == 0 ? filesize / threadcount : filesize / threadcount + 1;
    //sd卡里边指定的保存网络端下载下来的文件
                    File file = new File(filePath);
    //                启动每个线程,分别下载所分配的长度
                    for (int i = 0; i < threadcount; i++) {
                        threads[i] = new FileDownloadThread(file,url,(i+1),blockSize);
                        threads[i].setName("Thread:" + i);
                        threads[i].start();
                    }
    //是否下载完成
                    boolean isfinished = false;
    //                下载的总长度
                    int downloadAllsize = 0;
                    while (!isfinished) {
                        isfinished = true;
                        downloadAllsize = 0;
                        for (int i = 0; i < threadcount; i++) {
                            downloadAllsize += threads[i].getDownloadlenght();
                            if (!threads[i].isCompleted()) {
                                isfinished = false;
                            }
                        }
    //                    通知handler去更新
                        Message message = new Message();
                        message.getData().putInt("size", downloadAllsize);
                        MainActivity.handler.sendMessage(message);
                        Thread.sleep(1000);
                    }
                    Log.e(TAG, "run:下载的总大小: "+ downloadAllsize);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    class FileDownloadThread extends Thread {
        /**
         *  文件保存路径 
         */
        private File file;
        /**
         *  文件下载路径 (文件网址)
         */
        private URL downloadUrl;
        /**
         *  当前下载线程ID 
         */
        private int threadId;
        /**
         *  线程下载数据长度 
         */
        private int blockSize;
        private int downloadlenght;
        private boolean isCompleted;
     
        public FileDownloadThread(File file, URL downloadUrl, int threadId, int blockSize) {
            this.file = file;
            this.downloadUrl = downloadUrl;
            this.threadId = threadId;
            this.blockSize = blockSize;
        }
     
     
        @Override
        public void run() {
            super.run();
            BufferedInputStream  bis=null;
     
            RandomAccessFile raf=null;
     
     
     
            try {
                HttpURLConnection conn = (HttpURLConnection) downloadUrl.openConnection();
                conn.setAllowUserInteraction(true);
    //         开始的位置
                int  startpos=blockSize*(threadId-1);
                int endpos=blockSize*threadId-1;
    //            设置当前线程下载的开始点和结束点
                conn.setRequestProperty("Range","bytes="+startpos+"-"+endpos);
                byte[] buffer=new byte[1024];
                bis=new BufferedInputStream(conn.getInputStream());
                raf=new RandomAccessFile(file,"rwd");
                raf.seek(startpos);
                int len=0;
                while((len=bis.read(buffer,0,1024))!=-1){
                    raf.write(buffer,0,len);
                    downloadlenght+=len;
                }
                isCompleted=true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    //每个线程下载的数据长度
        public int getDownloadlenght() {
            return downloadlenght;
        }
    //返回线程是否下载完成
        public boolean isCompleted() {
            return isCompleted;
        }
    }

    FileDownloadThread类

    class FileDownloadThread extends Thread {
        /**
         *  文件保存路径 
         */
        private File file;
        /**
         *  文件下载路径 (文件网址)
         */
        private URL downloadUrl;
        /**
         *  当前下载线程ID 
         */
        private int threadId;
        /**
         *  线程下载数据长度 
         */
        private int blockSize;
        private int downloadlenght;
        private boolean isCompleted;
     
        public FileDownloadThread(File file, URL downloadUrl, int threadId, int blockSize) {
            this.file = file;
            this.downloadUrl = downloadUrl;
            this.threadId = threadId;
            this.blockSize = blockSize;
        }
     
     
        @Override
        public void run() {
            super.run();
            BufferedInputStream  bis=null;
     
            RandomAccessFile raf=null;
     
     
     
            try {
                HttpURLConnection conn = (HttpURLConnection) downloadUrl.openConnection();
                conn.setAllowUserInteraction(true);
    //         开始的位置
                int  startpos=blockSize*(threadId-1);
                int endpos=blockSize*threadId-1;
    //            设置当前线程下载的开始点和结束点
                conn.setRequestProperty("Range","bytes="+startpos+"-"+endpos);
                byte[] buffer=new byte[1024];
                bis=new BufferedInputStream(conn.getInputStream());
                raf=new RandomAccessFile(file,"rwd");
                raf.seek(startpos);
                int len=0;
                while((len=bis.read(buffer,0,1024))!=-1){
                    raf.write(buffer,0,len);
                    downloadlenght+=len;
                }
                isCompleted=true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    //每个线程下载的数据长度
        public int getDownloadlenght() {
            return downloadlenght;
        }
    //返回线程是否下载完成
        public boolean isCompleted() {
            return isCompleted;
        }
    }

    详细配置信息可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/28/net%e6%96%87%e4%bb%b6%e6%89%b9%e9%87%8f%e4%b8%8b%e8%bd%bd/
  • 相关阅读:
    java 类加载器的委托机制
    java 类加载器
    java 泛型
    java 注解(Annotation)
    java 内省综合案例和Beanutils工具包
    java 内省 了解JavaBean
    Java中的接口
    hdu 1853 Cyclic Tour 最大权值匹配 全部点连成环的最小边权和
    extjs fileuploadfield default value
    linux程序设计——套接字选项(第十五章)
  • 原文地址:https://www.cnblogs.com/songsu/p/11459868.html
Copyright © 2011-2022 走看看