- 浏览: 27424 次
- 性别:
- 来自: 上海
-
最新评论
本篇文章以你文件下载中的多线程下载以及断点续传为问题出发点,主要回顾一下多线程在实际开发中的应用和具体实现。
多线程下载的关键点在于对一个下载任务进行切分,即计算每个任务线程对应的实际文件中的起始点和终止点。在每个线程中采用数据流方式对远程文件进行连接,这里有个知识点,即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); } } }
相关推荐
在IT领域,多线程下载和断点续传是提高下载效率和用户体验的重要技术。这里,我们将深入探讨这两个概念,并结合使用HttpURLConnection实现的多线程下载工具进行讲解。 首先,多线程下载是一种利用网络资源的方式,...
然而,实现多线程断点续传需要解决几个问题: 1. **同步管理**:多个线程可能会同时访问同一个文件的部分,因此需要使用`synchronized`关键字或`Lock`对象来确保并发安全。 2. **断点信息共享**:每个线程需要知道...
1. 把每个下载文件切成若干个块(Block),然后得到一个位图,用来标记每个块的下载情况,并保存到文件里,用于实现断点续传。 2. HTTP Header里增加Range,如果服务器返回Cotent-Range 说明服务器支持文件定位,可以...
而"多线程"和"断点"这两个文件名可能是指相关示例代码或文档,可以进一步帮助你理解和实践Java FTP的多线程下载和断点续传。 在实际应用中,还需要考虑其他因素,如错误处理、网络状况的监控、文件完整性检查等。...
Java多线程断点续传下载是一个复杂但实用的技术,尤其在处理大文件或网络不稳定时,能够提高用户体验并优化资源利用。以下是对这个主题的详细解析: **1. Java多线程** Java多线程是指在一个Java应用程序中同时执行...
### Java多线程下载与断点续传技术详解 #### 一、背景介绍 随着互联网技术的发展,数据传输成为日常开发中的重要环节之一。在实际应用中,常常需要下载大文件,例如视频、大型应用程序等。传统的单线程下载方式在...
通过以上步骤,我们可以构建一个功能完备的Java多线程断点续传下载程序。这个项目不仅可以帮助初学者理解多线程和网络编程的基本概念,也可以作为实际项目开发中的一个参考模板。对于想要深入研究Java网络编程和并发...
### Java实现FTP多线程断点续传:深入解析与技术要点 在现代软件开发中,数据传输是一项基本且关键的任务,特别是在处理大文件时,断点续传功能显得尤为重要。断点续传允许在网络连接中断后恢复传输,避免了重新...
在Java编程中,多线程下载和断点续传是两个关键的概念,它们在处理大文件下载时尤其重要。这两个技术结合使用可以显著提高下载效率并优化用户体验。 **多线程下载** 多线程下载是一种将文件分割成多个部分,然后...
在Java中实现一个多线程断点续传的下载器,一般步骤如下: 1. 分割文件:根据文件大小和期望的线程数,计算每个线程需要下载的数据块大小。 2. 创建线程池:使用`ExecutorService`,如`Executors....
标题中的“socket做的支持多线程断点上传or断点续传Java源码”涉及到的是在网络编程中,如何使用Java的Socket API实现一个能够处理断点上传和断点续传功能的服务。这是一个高级的网络编程任务,通常在大型文件传输...
java实现FTP多线程断点续传,上传下载! - java学习与交流 - j2ee学习网 - j2ee学习网 (2012年5月21日) 用 Java 实现断点续传 (HTTP) (2012年5月21日) Java写的支持断点续传的FTP--crybaby的博客 (2012年5月21日) ...
总结来说,Java实现的多线程断点续传涉及的技术点包括: 1. 并发编程:使用`ExecutorService`、`CountDownLatch`进行线程管理和同步。 2. 文件操作:分析和合并临时文件,实现断点续传。 3. 网络I/O:通过`...
总结来说,Java中的多线程断点续传结合了并发处理和状态管理,通过分割文件并行处理,提高了文件传输效率,同时通过记录和恢复断点,实现了在网络不稳定情况下的可靠性。这是一项对大型文件上传和下载非常重要的技术...
Java多线程断点续传下载程序是一种高级的软件实现技术,它结合了Java的并发处理能力和文件传输的策略,以提高下载效率和用户体验。在这个项目中,我们主要关注两个核心概念:多线程和断点续传。 首先,多线程是Java...
在Android平台上,开发一款支持多线程断点续传功能的下载工具是一项技术挑战,它涉及到网络编程、文件处理以及线程管理等多个方面。这款名为"DownloadHelper"的项目,显然是一个致力于解决这些问题的开源解决方案。 ...
Java 断点续传与多线程下载是网络编程中两个重要的技术,它们在处理大文件下载时尤其有用。断点续传允许用户在下载中断后从上次停止的地方继续,而多线程下载则通过同时从服务器获取多个数据块来提高下载速度。接...
Java FTP多线程批量断点续传是一种在Java编程中实现高效、稳定文件传输的方法,尤其适用于大文件的上传和下载。在这个过程中,我们利用FTP(File Transfer Protocol)协议,结合多线程技术和断点续传功能,可以显著...
在Android开发中,多线程断点续传下载是一项重要的技术,它允许用户在中断下载后,从上次停止的地方继续下载,提高了用户体验。这个技术主要涉及到网络编程、多线程处理以及文件操作等多个方面。接下来,我们将深入...
Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多...