🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
上周时间基本都在做自己的项目了,所以很少来写博客了。今天上来更新下博客,内容是多线程下载,以冒一下泡。 多线程在一定程度下增快了下载的速度,但是最终下载速度还是决定于你的带宽,2G/3G网络下“带宽”这个词是否可以忽略?。。 其实如果文章名字改为多线程断点下载可能会屌一点,不过多线程下载和多线程断点下载的区别几乎只在于while循环的时候是否记录已经下载的文件块,断点下载记录了已经下载的文件块所以下次下载就能从断点开始下载(避免了重复下载),而下面这个代码没有记录,所以不具备这个功能。 多线程下载主要是用到下面这几个语句: ~~~ RandomAccessFile raf = new RandomAccessFile(PATH, "rwd"); raf.setLength(contentLength); ~~~ ~~~ conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); ~~~ ~~~ RandomAccessFile raf = new RandomAccessFile(PATH, "rwd"); raf.seek(startIndex); ~~~ 思路很简单:首先获得待下载文件的总长度,然后在本地生成一个一样大小的临时文件。然后将待下载的文件分块,让每个线程分别下载自己的文件块。非常要注意的是文件的下标。 ~~~ package com.example.mytest; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; /** * 该类会开三个线程下载URI的内容,下载到PATH文件夹内 * * @author Hehyu * */ public class Main extends Activity { private final String PATH = Environment.getExternalStorageDirectory() + "/finger/东京暗鸦.jpg"; private final String URI = "http://e.hiphotos.baidu.com/zhidao/pic/item/e850352ac65c1038a7b590ceb0119313b17e89f7.jpg"; private final int THREAD_COUNT = 3; private int contentLength = -1; private int blockSize = -1; private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { for (int threadId = 1; threadId <= THREAD_COUNT; threadId++) { int startIndex = (threadId - 1) * blockSize; int endIndex = threadId * blockSize - 1; if (threadId == THREAD_COUNT) { endIndex = contentLength; } System.out .println(threadId + " " + startIndex + " " + endIndex); // 开启一个线程进行下载 new downloadThread(threadId, startIndex, endIndex).start(); } }; }; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); new calSize().start(); } /** * 该线程专门负责计算文件总共长度,并且在本地生成一个同名同大小的文件 * * @author Hehyu * */ private class calSize extends Thread { @Override public void run() { // TODO Auto-generated method stub super.run(); URL url; try { url = new URL(URI); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); // 获取待下载文件长度 contentLength = conn.getContentLength(); blockSize = contentLength / THREAD_COUNT; RandomAccessFile raf = new RandomAccessFile(PATH, "rwd"); raf.setLength(contentLength); raf.close(); conn.disconnect(); // 已经获取了文件长度,通知主线程去创建子线程下载文件 Message msg = Message.obtain(); handler.sendMessage(msg); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 专门负责下载的进程 * * @author Hehyu * */ private class downloadThread extends Thread { private int threadId; private int startIndex; private int endIndex; public downloadThread(int threadId, int startIndex, int endIndex) { // TODO Auto-generated constructor stub this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { // TODO Auto-generated method stub super.run(); try { RandomAccessFile raf = new RandomAccessFile(PATH, "rwd"); raf.seek(startIndex); URL url = new URL(URI); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); int code = conn.getResponseCode(); InputStream is = conn.getInputStream(); int len = 0; byte[] buffer = new byte[1024]; while ((len = is.read(buffer)) != -1) { raf.write(buffer, 0, len); } raf.close(); conn.disconnect(); System.out.println("线程" + threadId + "下载完毕.."); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } ~~~