- 浏览: 103768 次
- 性别:
- 来自: 杭州
最新评论
-
whatlonelytear:
赞
java注解应用实例 - Annotation, 自定义注解, 注解类规则 -
砚台观月:
你好,例子还有吗,我想要份学习看下。提供的链接找不到了。
java网络编程之Http多线程下载应用实例 -
xianghanscce:
...
java泛型应用实例 - 自定义泛型类,方法 -
yhx1231:
...
Java反射应用实例 -
beiyeren:
写的不错啊
java注解应用实例 - Annotation, 自定义注解, 注解类规则
本demo 通过RandomAccessFile, URLConnection和多线程机制实现了Http下载功能. 从 这里 可以下载到完整的java代码工程: http://download.csdn.net/detail/hejiangtao /4029935. 相对于别的网上的例子来看, 本demo 是可运行的, 可以判断网络资源是否支持分段下载. 你是否遇到了java下载的图片 显示不出来或者RAR解压不了的情况, 可以参考本demo的解决方案
设计思路:
1. 首先读取文件的长度, 并判断网站是否支持分段下载
2. 如果支持分段下载则创建多个线程同时下载该文件,否则使用单线程下载
3. 在各个线程中,分别使用 RandomAccessFile对象写入对应的文件位置
具体实现解析:
1. 为了方便理解,先把util类贴出来.
SysValue.java:
在实际应用中,这些参数应该可以在界面配置或者配置文件配置.
HttpProcess.java:[java] view plain copy
- package com.ross.httpdownload.util;
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * Date: 2012-1-18
- * Since: MyJavaExpert v1.0
- * Description:
- */
- public class SysValue
- {
- //constant values
- //maximum number of the download thread
- public static int MAX_Num_Of_Thread = 3 ;
- //download file store path
- public static String Save_As_Path = "E:/myspace/download/" ;
- //buffer size
- public static int Buffer_Size = 1024 ;
- }
将Http相关的公共操作放在这个类里面,避免写重复代码.
[java] view plain copy
- package com.ross.httpdownload.util;
- import java.io.IOException;
- import java.net.*;
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * Date: 2012-1-18
- * Since: MyJavaExpert v1.0
- * Description: This class will provide the common process of http
- */
- public class HttpProcess
- {
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * Description: get an object of opened URL connection
- * @param sURL: completed URL string
- * @return oHttpURLCon: an object of opened URL connection
- * @throws IOException
- */
- public URLConnection getURLConnection(String sURL) throws IOException
- {
- URLConnection oURLCon = null ;
- // replace space with '+' in the URL string
- if ( null != sURL)
- {
- sURL = sURL.replaceAll("\\s" , "+" );
- // generate URL
- URL oURL = new URL(sURL);
- oURLCon = (URLConnection) oURL.openConnection();
- }
- return oURLCon;
- }
- }
2. 看我们的多线程下载实现
a. 首先看下如何判断网站资源是否支持分段下载
很 多网络资源,即使在java里面设置了http的InputStream流的范围后, 取的的流的长度还是整个文件的长度. 针对这种情况我就认为该资源不支持分段下载,也就是无法多线程下载了(使用原来的方式下载你就发现下载的图片只能显示一半,或者不能显示,RAR也是损坏 的, 字节不对吗 :)). 我也试过通过使用InputStream 流的skip方法跳过前面内容的方式实现多线程,但是事实证明,skip太不靠谱,跳的步长并不是一定的,哎什么玩意,只好放弃.
[java] view plain copy
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * Description: Check whether the server support multiple thread download or not
- * @param sURL: the download file URL
- * @return bRet: true - support, false - not support
- * @throws IOException
- */
- public boolean isSupportMultipleThreadDown(String sURL) throws IOException
- {
- boolean bRet = true ;
- // get URL connection
- URLConnection oURLCon = oHttpProcess.getURLConnection(sURL);
- // set the resource range
- oURLCon.setRequestProperty("Range" , "bytes=" + 0 + "-" + 1023 );
- if ( 1024 < oURLCon.getContentLength())
- {
- bRet = false ;
- }
- return bRet;
- }
b. 然后我们看下如何,将文件分段下载1) 首先是预处理
先是做了个简单的判断,防止线程过多或者小于1; 然后判断网络资源是否支持分段下载,如果不支持则将线程数重置为1; 在获取整个文件长度后, 使用总长度除以线程数得出每个线程负责下载的字节范围.
2) 使用线程池管理并启动多线程下载
DownloadTread就是我们的线程下载实现类, 后面会单独说明. 众所周知java下标是从0开始的,所以各个线程分配字节范围的时候,要考虑进去. 将对应分配的字节范围,URL,文件名信息设置给DownloadTread对象后,使用ExecutorService启动线程.
3)当然不要忘记在finally里面调用线程池的关闭方法.
[java] view plain copy
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * Description: download tool entry method
- * @param sURL: the completed URL of the file, which is wanted to download.
- * @param Num: Number of concurrent download thread
- * @param sSaveAsName: the the file name saved in disk, like: myphoto.jpg
- */
- public void download(String sURL, int iNumOfThread, String sSaveAsName)
- {
- long lFileLen = 0 ;
- long lFileSegementLen = 0 ;
- long iLeft = 0 ;
- URLConnection oURLCon = null ;
- String sFullFileName = SysValue.Save_As_Path + sSaveAsName;
- if (iNumOfThread > SysValue.MAX_Num_Of_Thread)
- {
- iNumOfThread = SysValue.MAX_Num_Of_Thread;
- }
- if (iNumOfThread < 1 )
- {
- iNumOfThread = 1 ;
- }
- // build the thread pool to manage the thread
- ExecutorService oExecService = Executors
- .newFixedThreadPool(iNumOfThread);
- try
- {
- if (!isSupportMultipleThreadDown(sURL))
- {
- System.out
- .println("This site do not support multiple thread download, reset the thread to 1" );
- iNumOfThread = 1 ;
- }
- // get URL connection
- oURLCon = oHttpProcess.getURLConnection(sURL);
- // get the length of the file
- lFileLen = oURLCon.getContentLength();
- // split the length of the file according to the number of thread.
- lFileSegementLen = lFileLen / iNumOfThread;
- iLeft = lFileLen % iNumOfThread;
- for ( int i = 0 ; i < iNumOfThread; i++)
- {
- // initial the thread data
- DownloadThread oDownloadThread = new DownloadThread();
- oDownloadThread.setIThreadId(i);
- // Start index of the current thread
- oDownloadThread.setLStartIndex(i * lFileSegementLen);
- // last thread will take all the rest content
- if (i == (iNumOfThread - 1 ))
- {
- oDownloadThread.setLEndIndex((i + 1 ) * lFileSegementLen
- + iLeft - 1 );
- }
- else
- {
- oDownloadThread
- .setLEndIndex((i + 1 ) * lFileSegementLen - 1 );
- }
- // set save file name with path
- oDownloadThread.setSFullFileName(sFullFileName);
- // set URL
- oDownloadThread.setSFileURL(sURL);
- // execute the download thread
- oExecService.execute(oDownloadThread);
- }
- System.out.println("the file is stored as \"" + sFullFileName
- + "\"." );
- System.out.println("the file length is " + lFileLen + "." );
- }
- catch (IOException e)
- {
- System.out.println("download the file failed, IO Exception"
- + e.getMessage());
- e.printStackTrace();
- }
- finally
- {
- oExecService.shutdown();
- }
- }
c.最后就是我们的核心下载线程实现类了1) DownloadTread类实现了Runnalbe抽象接口, 实现了其run()方法.
2) 两个关键的地方一是通过使用URLConnection 的setRequestProperty方法设置本线程读取的流的范围, 另外一个是通过RandomAccessFile 的seek方法或者当前线程写入文件的位置, 一个字节都不能错哦,错了你的文件就有差错了, 还是要记住java下标是从0开始的.
3)然后通过循环从URLConnection的InputStream里面通过 buffer一组一组的读出来, 通过RandomAccessFile 对象一组一组的写入到目标文件里面(代码里面判断实际读取长度部分是不需要的, 可以去掉, 是我探索不支持分段下载网络资源的多线程下载方式时留下的).
4)需要提一下的是run()方法是没有输入参数的,所以我们通过增加类字段的方式将参数传入该方法.
[java] view plain copy
- package com.ross.httpdownload;
- import java.io.*;
- import java.net.*;
- import java.text.*;
- import java.util.Date;
- import com.ross.httpdownload.util.*;
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * Date: 2012-1-18
- * Since: MyJavaExpert v1.0
- * Description: download thread implementation.
- */
- public class DownloadThread implements Runnable
- {
- private String sFileURL;
- private long lStartIndex;
- private long lEndIndex;
- private int iThreadId;
- private String sFullFileName;
- private HttpProcess oHttpProcess;
- /**
- * Description: default constructor, it is used for initializing the fields.
- */
- public DownloadThread()
- {
- oHttpProcess = new HttpProcess();
- }
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * Description: it will implement the download logic
- */
- public void run()
- {
- System.out.println("The download thread "
- + this .iThreadId
- + " is started at "
- + (new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ))
- .format(new Date()));
- System.out.println("The download index of " + this .iThreadId + " is "
- + this .lStartIndex + " to " + this .lEndIndex);
- // content length
- long lContentlen = 0 ;
- // used to store the new url connection
- URLConnection oURLCon = null ;
- // used to store the input stream of the response
- BufferedInputStream oBIn = null ;
- // used to store the output writer
- RandomAccessFile oRAFile = null ;
- // create the buffer
- byte [] bBuffer = new byte [SysValue.Buffer_Size];
- // get URL connection
- try
- {
- // create a link for each thread
- oURLCon = oHttpProcess.getURLConnection(this .sFileURL);
- // allow the user interaction, for example: a verify pop window
- oURLCon.setAllowUserInteraction(true );
- // set the resource range
- oURLCon.setRequestProperty("Range" , "bytes=" + this .lStartIndex
- + "-" + this .lEndIndex);
- // get the url connection input stream
- oBIn = new BufferedInputStream(oURLCon.getInputStream());
- // initialize the random access file object
- oRAFile = new RandomAccessFile( this .sFullFileName, "rw" );
- oRAFile.seek(this .lStartIndex);
- // read the stream from http connection
- int iLen = 0 ;
- int iActualLen = 0 ;
- while (iActualLen < ( this .lEndIndex - this .lStartIndex + 1 ))
- {
- iLen = oBIn.read(bBuffer, 0 , SysValue.Buffer_Size);
- if (- 1 == iLen)
- {
- break ;
- }
- // write the read data to file
- oRAFile.write(bBuffer, 0 , iLen);
- // move the position mark
- iActualLen = iActualLen + iLen;
- }
- System.out.println("Thread " + this .iThreadId
- + " download is finished, totaly: " + iActualLen);
- }
- catch (IOException e)
- {
- System.out.println("download the file failed, IO Exception"
- + e.getMessage());
- e.printStackTrace();
- }
- finally
- {
- if ( null != oRAFile)
- {
- try
- {
- oRAFile.close();
- }
- catch (IOException e)
- {
- System.out
- .println("close object of RandomAccessFile failed, IO Exception"
- + e.getStackTrace());
- }
- }
- if ( null != oBIn)
- {
- try
- {
- oBIn.close();
- }
- catch (IOException e)
- {
- System.out
- .println("close input stream of http connection failed, IO Exception"
- + e.getStackTrace());
- }
- }
- }
- System.out.println("The download thread "
- + this .iThreadId
- + " is ended at "
- + (new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ))
- .format(new Date()));
- }
- //省略了set/get方法
- }
来测试下我们的实现:
看下我们的main函数, 我们就通过3个例子来测试我们的实现: 一个可以多线程下载的zip文件,一个可以多线程下载的图片,一个不能多线程下载图片.
MyMain.java:
[java] view plain copy
- package com.ross.httpdownload;
- import com.ross.httpdownload.util.*;
- /**
- * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com
- * Date: 2012-1-19
- * Since: MyJavaExpert v1.0
- * Description: Test the download tool class
- */
- public class MyMain
- {
- public static void main(String[] args)
- {
- // set system configuration, in real software, it can be configured
- // through GUI, file,etc.
- SysValue.MAX_Num_Of_Thread = 3 ;
- SysValue.Save_As_Path = "E:/myspace/download/" ;
- SysValue.Buffer_Size = 1024 ;
- //file web address
- //String sFileURL = "http://xinsheng-image.huawei.com/cn/forumimage/showimage-991441-20990f56c5b11261fa63e969d8d5580c-self.jpg";
- //String sFileURL = "http://lh5.googleusercontent.com/-F7a0loCDyoQ/AAAAAAAAAAI/AAAAAAAAAFY/TrDxSDdQuhQ/s512-c/photo.jpg";
- //String sFileURL = "http://xinsheng-image.huawei.com/cn/forumimage/showimage-816607-f61c8fe14fc359d49b044376a0956acd-self.jpg";
- //String sFileURL = "http://3.bp.blogspot.com/-oVO24VW8F6M/TxJ9O0opP3I/AAAAAAAAANY/anpu8S4FAC4/s640/100_9223.JPG";
- String sFileURL = "http://hi.csdn.net/attachment/201201/1/0_1325433530Bg5e.gif" ;
- sFileURL = "http://west263.newhua.com:82/down/jia-audio-converter.zip" ;
- //file save as name
- String sFileName = sFileURL.substring(sFileURL.lastIndexOf("/" ) + 1 );
- // create a object of download tool
- HttpDownloadTool oHttpDownloadTool = new HttpDownloadTool();
- // download the file
- oHttpDownloadTool.download(sFileURL, 3 , sFileName);
- }
- }
a. 可以多线程下载的zip文件测试
URL: http://west263.newhua.com:82/down/jia-audio-converter.zip
线程数: 3
控制台打印信息:
下载的文件抓图:[plain] view plain copy
- the file is stored as "E:/myspace/download/jia-audio-converter.zip".
- the file length is 5720120.
- The download thread 1 is started at 2012-01-21 00:49:23
- The download index of 1 is 1906706 to 3813411
- The download thread 0 is started at 2012-01-21 00:49:23
- The download index of 0 is 0 to 1906705
- The download thread 2 is started at 2012-01-21 00:49:23
- The download index of 2 is 3813412 to 5720119
- Thread 0 download is finished, totaly: 1906706
- The download thread 0 is ended at 2012-01-21 00:58:09
- Thread 1 download is finished, totaly: 1906706
- The download thread 1 is ended at 2012-01-21 01:06:17
- Thread 2 download is finished, totaly: 1906708
- The download thread 2 is ended at 2012-01-21 01:07:05
b.可以多线程下载的图片测试
URL: http://hi.csdn.net/attachment/201201/1/0_1325433530Bg5e.gif
线程数: 3
控制台打印信息:
下载的文件抓图:[plain] view plain copy
- the file is stored as "E:/myspace/download/0_1325433530Bg5e.gif".
- the file length is 23304.
- The download thread 2 is started at 2012-01-21 02:03:00
- The download thread 0 is started at 2012-01-21 02:03:00
- The download index of 2 is 15536 to 23303
- The download index of 0 is 0 to 7767
- The download thread 1 is started at 2012-01-21 02:03:00
- The download index of 1 is 7768 to 15535
- Thread 2 download is finished, totaly: 7768
- The download thread 2 is ended at 2012-01-21 02:03:01
- Thread 1 download is finished, totaly: 7768
- The download thread 1 is ended at 2012-01-21 02:03:01
- Thread 0 download is finished, totaly: 7768
- The download thread 0 is ended at 2012-01-21 02:03:02
c. 不能多线程下载图片
URL: http://3.bp.blogspot.com/-oVO24VW8F6M/TxJ9O0opP3I/AAAAAAAAANY/anpu8S4FAC4/s640/100_9223.JPG
线程数: 3
控制台打印信息:
下载的文件抓图:[plain] view plain copy
- This site do not support multiple thread download, reset the thread to 1
- the file is stored as "E:/myspace/download/100_9223.JPG".
- the file length is 170398.
- The download thread 0 is started at 2012-01-21 02:06:54
- The download index of 0 is 0 to 170397
- Thread 0 download is finished, totaly: 170398
- The download thread 0 is ended at 2012-01-21 02:06:55
到这里整个demo完成了.
注: 转载请注明出处: http://hejiangtao.iteye.com , 用于商业得给我分成
发表评论
-
<转>NetBeans 6.1 界面语言设置
2012-10-07 01:49 2354NetBeans 6.1 界面语言设置从官网下载的NetBea ... -
常见开源协议(BSD,Apache,GPL,LGPL,MIT)
2012-10-05 01:52 996BSD开源协议(original BSD license、Fr ... -
Java相对路径总结<转>
2012-03-04 17:16 10441.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或 ... -
Java Compiler 应用实例
2012-02-09 01:22 7074一直在用JDK1.5, 一直搞不清楚JDK1.6有啥特性, 就 ... -
java注解应用实例 - Annotation, 自定义注解, 注解类规则
2012-01-29 21:35 25683本文介绍了java的自定义注解及注解类编写的规则, 并通过实例 ... -
Java 序列化的高级认识--序列化反序列化, 加密存储<转>
2012-01-29 15:21 2316简介: 文章对序列化进行了更深一步的讨论,用实际的例子 ... -
Java反射应用实例
2012-01-14 23:43 2157本文主要通过Java反射 ... -
java反射的性能问题 (转)
2012-01-14 23:36 2284很多IOC,还有框架都使用反射。特别是在通过反射调用方法的时候 ... -
java泛型应用实例 - 自定义泛型类,方法
2012-01-14 23:19 37516注: 转载请注明出处: http://hejiangtao.i ... -
泛型的效率和原始类的效率比较(转)
2012-01-14 23:16 1859用 了好久的泛型,突然听到有人说:泛型影响效率! 嘿, ... -
文本数据库的简单java实现
2012-01-14 22:58 7253注: 转载请注明出处: ...
相关推荐
Java网络编程案例教程习题参考答案涵盖了Java网络编程的基础知识点,包括Socket编程、TCP/IP协议、Java Socket类、ServerSocket类、Java网络编程模型、网络编程常见问题、多线程编程、并发编程、Socket选项、网络...
Java网络编程是Java开发中的重要领域,它涵盖了网络应用程序的设计、实现和调试。在这个主题下,我们可以探讨多个关键知识点: 1. **Java Socket编程**:Java的Socket类提供了基于TCP/IP协议的网络通信能力。通过...
Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,极大地提升了程序的效率和性能。在Java中,实现多线程有两种主要方式:通过实现Runnable接口或者继承Thread类。本案例将深入探讨Java多线程中的关键...
4. **多线程处理**:在网络编程中,为了同时处理多个客户端请求,通常需要使用多线程。Java的Thread类和Runnable接口是实现并发处理的关键。 5. **输入/输出流**:网络编程涉及数据的发送和接收,因此理解和掌握I/O...
在Java编程领域,多线程是一项至关重要的技术,它使得程序可以同时执行多个任务,从而提高了系统的效率和响应性。本书“Java多线程编程实例”深入浅出地讲解了如何在Java环境中实现多线程操作,尽管出版时间较早,但...
以上就是Java多线程编程的关键点,理解并熟练运用这些概念和工具,能够帮助开发者编写出高效、稳定的多线程应用程序。在实际工作中,应结合具体需求和场景,选择合适的方法来实现并发控制,提高程序性能。
本文将深入探讨多线程编程实例及其在网络编程中的应用。 首先,理解多线程的概念是必要的。线程是操作系统分配CPU时间的基本单元,一个进程中可以包含多个线程。多线程编程允许开发者创建并行运行的任务,这些任务...
总的来说,这个Java网络编程TCP多线程连接例子为我们提供了一个基础的框架,展示了如何使用Java实现可靠的TCP连接,并通过多线程处理并发请求。在深入学习和实践中,我们还可以结合其他Java网络库,如NIO(非阻塞I/O...
《Java2.0网络多线程编程实例教程》是一本由李荣贵等人编写的书籍,专注于Java2.0(即Java SE 2)平台下的网络编程和多线程技术。该书通过丰富的实例,旨在帮助读者深入理解和掌握这两项核心的Java开发技能。 在...
多线程编程是Java 网络编程中的一种常用的编程方法。多线程编程可以使得程序同时执行多个任务,提高程序的性能和响应速度。在本实验中,我们使用多线程编程来实现客户端和服务器端的通信。 知识点7:网络编程中的...
《Java多线程编程实战指南-核心篇》是一本深入探讨Java并发编程的书籍,旨在帮助读者掌握在Java环境中创建、管理和同步线程的核心技术。Java的多线程能力是其强大之处,使得开发者能够在同一时间执行多个任务,提高...
从给定的文件信息中,我们可以提取出关于Java多线程...以上是Java多线程编程的基础知识点,理解这些概念对于开发高效、健壮的多线程应用程序至关重要。通过实际操作和不断实践,可以更深入地掌握Java多线程编程的精髓。
3. **多线程与并发**:在网络编程中,多线程和并发处理是必不可少的,书中会讲解如何在Java中管理线程,以及如何处理并发问题,如同步和锁机制。 4. **URL和HTTP**:Java通过URL类提供了访问Web资源的能力,而HTTP...
Java网络编程是开发分布式应用程序的关键技术,它允许程序通过网络发送和接收数据。《Java网络编程实例》这本书的源代码提供了丰富的示例,帮助读者深入理解这一领域。本压缩包包含的源代码覆盖了Java网络编程的各种...
在Java编程中,多线程是一项关键技能,尤其在处理并发任务时,如我们的示例——"Java多线程下载网络图片"。这个场景展示了如何利用多线程技术提高程序性能,减少用户等待时间,同时优化系统资源的使用。下面我们将...
Java多线程编程实战指南...本书以基本概念、原理与方法为主线,辅以丰富的实战案例和生活化实例,并从Java虚拟机、操作系统和硬件多个层次与角度出发,循序渐进、系统地介绍Java平台下的多线程编程核心技术及相关工具。
《汪文君JAVA多线程编程实战》是一本专注于Java多线程编程的实战教程,由知名讲师汪文君倾力打造。这本书旨在帮助Java开发者深入理解和熟练掌握多线程编程技术,提升软件开发的效率和质量。在Java平台中,多线程是...
Java网络编程是Java开发中的重要领域,它涵盖了网络通信的所有基本概念和技术,包括TCP/IP协议、套接字(Socket)编程、多线程、HTTP、HTTPS等。在本资料中,《Java网络编程》第三版提供了深入浅出的讲解,旨在帮助...
Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过继承Thread类或实现Runnable接口来实现。本教程将深入探讨Java多线程的各个方面...
5. **多线程处理**:在网络编程中,尤其是服务器端,通常需要同时处理多个客户端请求,这就需要用到Java的多线程技术。线程可以使服务器同时处理多个连接,提高服务效率。 6. **异常处理**:网络编程中,网络中断、...