- 浏览: 26738 次
- 性别:
- 来自: 上海
最新评论
本篇文章以你文件下载中的多线程下载以及断点续传为问题出发点,主要回顾一下多线程在实际开发中的应用和具体实现。
多线程下载的关键点在于对一个下载任务进行切分,即计算每个任务线程对应的实际文件中的起始点和终止点。在每个线程中采用数据流方式对远程文件进行连接,这里有个知识点,即http头Rander参数,详见http://guoba6688-sina-com.iteye.com/blog/786036,通过该参数可以实现读取远程文件的指定部分。
下面的实例的应用环境为android,具体看代码:
以上为线程下载任务,主要负责下载任务,下面看一下管理器
该管理器主要的任务是分割下载任务,对线程的管理(通过statu参数)、以及各线程下载完成后文件的合并等。
下面是实际中的调用:
多线程下载的关键点在于对一个下载任务进行切分,即计算每个任务线程对应的实际文件中的起始点和终止点。在每个线程中采用数据流方式对远程文件进行连接,这里有个知识点,即http头Rander参数,详见http://guoba6688-sina-com.iteye.com/blog/786036,通过该参数可以实现读取远程文件的指定部分。
下面的实例的应用环境为android,具体看代码:
package com.fsti.android.foyer.net; 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 android.util.Log; /** * 文件下载线程 * * @author ilikeido * @modifyAuthor * * @creatTime 2011-4-7 下午02:59:04 */ public class FileDownloadThread extends Thread { private static final int BUFFER_SIZE = 1024; private URL url;//地址 private File file;//保存文件 private int startPosition;//开始位置 private int endPosition;//结束位置 private int curPosition;//当前位置 private ThreadCutter cutter; // 用于标识当前线程是否下载完成 private boolean finished = false; private int downloadSize = 0;//下载的文件大小 public FileDownloadThread(URL url, File file, int startPosition, int endPosition,ThreadCutter cutter) { this.url = url; this.file = file; this.startPosition = startPosition; this.curPosition = startPosition; this.endPosition = endPosition; this.cutter = cutter; } @Override public void run() { BufferedInputStream bis = null; RandomAccessFile fos = null; byte[] buf = new byte[BUFFER_SIZE]; URLConnection con = null; try { fos = new RandomAccessFile(file, "rw"); downloadSize = (int) fos.length(); con = url.openConnection(); con.setAllowUserInteraction(true); // 设置当前线程下载的起点,终点 con.setRequestProperty("Range", "bytes=" + (startPosition+downloadSize) + "-" + endPosition); // 使用java中的RandomAccessFile对文件进行随机读写操作 curPosition = startPosition + downloadSize; // 设置开始写文件的位置 fos.seek(downloadSize); bis = new BufferedInputStream(con.getInputStream()); // 开始循环以流的形式读写文件 while (cutter.getStatu() == 1 && curPosition < endPosition) { int len = bis.read(buf, 0, BUFFER_SIZE); if (len == -1) { break; } fos.write(buf, 0, len); curPosition = curPosition + len; if (curPosition > endPosition) { downloadSize += len - (curPosition - endPosition) + 1; } else { downloadSize += len; } } // 下载完成设为true this.finished = true; bis.close(); fos.close(); } catch (IOException e) { Log.d(getName() + "Error:", e.getMessage()); } } public boolean isFinished() { return finished; } public int getDownloadSize() { return downloadSize; } public File getFile(){ return file; } }
以上为线程下载任务,主要负责下载任务,下面看一下管理器
package com.fsti.android.foyer.net; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import android.util.Log; /** * 文件分割器(用于多线程下载) * * @author ilikeido * @modifyAuthor * * @creatTime 2011-4-7 下午03:05:53 */ public class DownThreadManager { private static final String TAG = "ThreadCutter"; private int threadSize;// 线程数 private URL url;// 地址 private String fileName; private int totalProgress;// 整体进度 private int filelength;// 文件大小 File dir; File saveFile; private int statu;// 状态 0:停止 1:正常 2:暂停 3:完成 -1:错误 private List<FileDownloadThread> threads; public DownThreadManager(int threadSize, String urlStr, File dir) throws IOException { this.dir = dir; this.threadSize = threadSize; this.url = new URL(urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); filelength = conn.getContentLength(); if(filelength>0){ initFileName(conn,urlStr); cutThreads(); }else{ throw new RuntimeException("file not find"); } } /** * 分割下载任务 */ private void cutThreads() { threads = new ArrayList<FileDownloadThread>(); int cutsize = filelength / threadSize; for (int i = 0; i < threadSize; i++) { File tempFile = new File(dir, fileName + i + ".temp"); int startPosition = cutsize * i; int endPosition = 0; FileDownloadThread thread = null; if (i < threadSize - 1) { endPosition = cutsize * i + cutsize - 1; thread = new FileDownloadThread(url, tempFile, startPosition, endPosition, this); } else { thread = new FileDownloadThread(url, tempFile, startPosition, filelength, this); } threads.add(thread); } } /** * 开始下载任务 */ public void start() { Iterator<FileDownloadThread> itertor = threads.iterator(); statu = 1; while (itertor.hasNext()) itertor.next().start(); } /** * 获取当前下载的文件大小 * * @return */ public int getDownloadSize() { Iterator<FileDownloadThread> itertor = threads.iterator(); int downloadSize = 0; while (itertor.hasNext()) { downloadSize += itertor.next().getDownloadSize(); } if (downloadSize > 0) { this.totalProgress = (int) (((float) downloadSize / filelength) * 100); } if (downloadSize == filelength) { this.statu = 3; } return downloadSize; } public void merge() throws IOException { RandomAccessFile ok = new RandomAccessFile(saveFile,"rw"); Iterator<FileDownloadThread> itertor = threads.iterator(); while (itertor.hasNext()) { File file = itertor.next().getFile(); RandomAccessFile read = new RandomAccessFile(file, "r"); byte[] b = new byte[1024]; int n = 0; while ((n = read.read(b)) != -1) { ok.write(b, 0, n); } read.close(); file.delete(); } ok.close(); } public void stop() { this.statu = 2; } public int getStatu() { return statu; } public void setStatu(int statu) { this.statu = statu; } public int getTotalProgress() { return totalProgress; } /** * 获取文件名 * * @param http */ public void initFileName(HttpURLConnection http,String urlStr) { String filename = urlStr.substring(urlStr.lastIndexOf('/') + 1); if(filename.indexOf(".")>=0){ fileName = filename; }else{ Map<String, String> header = getHttpResponseHeader(http); for (Map.Entry<String, String> entry : header.entrySet()) { String key = entry.getKey() != null ? entry.getKey() + ":" : ""; print(key + entry.getValue()); } String dispostion = header.get("content-disposition"); int index = 0; if((index = dispostion.indexOf("filename")) >-1){ String filenametemp = dispostion.substring(index,dispostion.length()); String[] temp = filenametemp.split("\""); fileName = temp[1]; } } saveFile = new File(dir, fileName); } /** * 获取Http响应头字段 * * @param http * @return */ public static Map<String, String> getHttpResponseHeader( HttpURLConnection http) { Map<String, String> header = new LinkedHashMap<String, String>(); for (int i = 0;; i++) { String mine = http.getHeaderField(i); if (mine == null) break; header.put(http.getHeaderFieldKey(i), mine); } return header; } private static void print(String msg) { Log.i(TAG, msg); } public File getSaveFile(){ return this.getSaveFile(); } }
该管理器主要的任务是分割下载任务,对线程的管理(通过statu参数)、以及各线程下载完成后文件的合并等。
下面是实际中的调用:
package com.fsti.android.foyer; import java.io.File; import java.io.IOException; import android.app.Activity; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import com.fsti.android.foyer.net.ThreadCutter; public class MainActivity extends Activity implements OnClickListener,DialogInterface.OnClickListener{ /** Called when the activity is first created. */ ProgressDialog dialog = null; int threadNum = 2; String urlStr= "http://www.piaoao.com/resources/updatefiles/alldown/WingLetter_GPiaoao.apk";//"http://nutla.googlecode.com/files/Nuta9.pdf";//"http://dl_dir.qq.com/qqfile/qq/Android/Tencent_Wblog%20V2.0.1.apk";// ThreadCutter cutter = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button button = (Button) findViewById(R.id.button1); button.setOnClickListener(this); } @Override public void onClick(View arg0) { dialog = new ProgressDialog(this); dialog.setProgress(59); dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); dialog.setTitle("下载中"); dialog.setMessage("正在下载应用程序"); dialog.setButton("取消", this); dialog.show(); download(); } @Override public void onClick(DialogInterface arg0, int arg1) { cutter.stop(); dialog.dismiss(); } public void download(){ final File dir = Environment.getExternalStorageDirectory(); int cutterNum = 3; try { cutter = new ThreadCutter(cutterNum, urlStr, dir); Runnable runnable = new Runnable() { @Override public void run() { cutter.start(); while(cutter.getTotalProgress() < 100){ cutter.getDownloadSize(); try { Thread.sleep(900); } catch (InterruptedException e) { e.printStackTrace(); } dialog.setProgress(cutter.getTotalProgress()); } try { cutter.merge(); cutter.setStatu(3); } catch (IOException e) { e.printStackTrace(); } dialog.dismiss(); try { if(cutter.getSaveFile().getAbsolutePath().endsWith(".apk")){ Intent localIntent1 = new Intent("android.intent.action.VIEW"); Uri localUri = Uri.fromFile(cutter.getSaveFile()); localIntent1.setDataAndType(localUri, "application/vnd.android.package-archive"); startActivity(localIntent1); } } catch (Exception e) { e.printStackTrace(); } } }; new Thread(runnable).start(); } catch (IOException e) { cutter.setStatu(4); } } }
相关推荐
1. 把每个下载文件切成若干个块(Block),然后得到一个位图,用来标记每个块的下载情况,并保存到文件里,用于实现断点续传。 2. HTTP Header里增加Range,如果服务器返回Cotent-Range 说明服务器支持文件定位,可以...
java FTP多线程 批量 断点续传,使用 1.建一个支持多线程FTP服务端; 如:xxftp有Windows和Linux版本; 2.建一个项目导入文件测试;
java 多线程下载和断点续传
java实现FTP多线程断点续传
刚刚整理的java断点续传,多线程处理,不知道怎么把多线程去掉
java 多线程断点续传 java 多线程断点续传 java 多线程断点续传
java相关的 ftp知识 如:ftp服务器、ftp主被动通讯模式、断点续传、单个文件多线程下载
java断点续传与多线程下载java断点续传与多线程下载java断点续传与多线程下载
多线程 断点续传 java 下载 java多线程实例
Java 多线程下载及断点续传示例
java实现FTP多线程断点续传,上传下载! - java学习与交流 - j2ee学习网 - j2ee学习网 (2012年5月21日) 用 Java 实现断点续传 (HTTP) (2012年5月21日) Java写的支持断点续传的FTP--crybaby的博客 (2012年5月21日) ...
该程序实现了java的多线程下载,显示下载进度条
这是java实现多线程断点续传下载功能的源代码,对于学习java网络编程、多线程等基础知识的同学有一定的参考作用,希望能够这个资源能够对你们有帮助
Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多...
socket做的支持多线程断点上传or断点续传Java源码
2、支持多任务多线程同时下载; 3、每个任务的线程数由用户在新建任务时自定义,缺省为5个线程; 4、任务下载过程中可以点击“线程+”或“线程-”即时增减线程; 5、选择任务,可以在任务信息栏中查看任务下载的信息...
JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多...
由于要写一个从第三方服务器...断点续传,多线程下载文件,idea开发工具需要安装 lombok 插件,具体百度下吧, 不过没有也没关系,我这里主要lombok 的set get、log 两个方法,具体自己可以重写 ,只为求分,git地址为...
支持断点续传java多线程下载.doc