求教批量下载文件的思路

时间:2021-05-03 09:54:07
我在用BlackBerry JDE(java1.3)开发应用,遇到批量下载的问题,下边是我使用的方法,请大神们给些建议~

我做的是知乎日报客户端,首先用一个线程获取json数据,在ui里添加列表显示所有项目内容,这一步没有问题

然后是下载每一个列表里的缩略图,一开始我只用了一个http connection循环下载,模拟器上没问题,因为电脑速度快,但是在设备上调试,会频繁抛出Stream Closed异常(但是所有缩略图都正确下载并显示了),我猜测的原因是,当第一个文件下载结束时调用http connection的close方法关闭连接,但是关闭需要一定的时间,与此同时第二个文件的下载开始了,因为是同一个连接,所以一边建立连接一边关闭连接就异常了,这是我的猜测。。。。。

接着我换了另一个方法,使用一个新线程,循环下载每一个文件,但是每一个下载都使用了一个新的http connection,也就是说,前一个连接关闭需要多久我不管它,反正有新的连接去下载后边的文件,这样做似乎解决了问题了

但是效率问题出现了,开始测试知乎api的时候只用主线程获取json数据并下载缩略图,虽然阻塞了,但是只要等一下下所有图片文字就都显示出来了(缩略图每个3k左右,一次最多10几个),用了现在这个方法,显示图片的时候就像是慢镜头,眼看着隔几秒显示出来一张,我感觉这个方法应该还是有问题的

再然后是下边的问题,因为日报数据是按日获取的,比如我刚刚打开了今天的内容,还没等缩略图下载完毕(因为上边的方法下载图片很慢很慢),就想看前一天的内容了,于是乎重新获取json数据,再一次下载所有缩略图,重复几次这个动作,就会抛出TooManyThread异常n次,我忘了黑莓设备允许同时运行的线程数是几十个还是100多个,但是理论上我重复一次上边的操作应该只会新增加一个线程才对,不可能抛出too many异常啊?难道每个下载连接也算一个线程了?

啰嗦了一堆只是为了描述清楚我的问题,总结一下我的问题其实只有两个,对于批量下载文件有没有什么更高效的方法,以及在第一次批量下载没结束的情况下开始第二次批量下载,怎么能有效的中断第一批次?鉴于这个app的特性,第一批次的数据和图片在第二批次开启时就可以作废了,所以不用考虑数据完整性问题

请大神们一定帮帮忙啊,谢谢啦!!!~

15 个解决方案

#1


你是想一个一个的下载,还是将要下载的文件打包zip文件后在下载

#2


两个建议:
1、用线程池来拉数据,避免随意开线程;
2、适当缓存已拉下来的数据,特别合适于解决你这种:“我刚刚打开了今天的内容,.....,就想看前一天的内容了”;
3、可以用另一个线程去强行关闭正在拉数据的连接,无非就是拉数据的线程会抛异常而已了;
4、如果能善用KeepAlive的话,可以减少创建新连接的时间开销;
5、如果能的话,适当合并所需拉取的文件数,比如把本来需要多次调用并得到多个JSON的合并为一次调用就可以得到一组JSON;当然这个需要你有修改服务端的能力才行。

#3


引用 2 楼 ldh911 的回复:
两个建议:
1、用线程池来拉数据,避免随意开线程;
2、适当缓存已拉下来的数据,特别合适于解决你这种:“我刚刚打开了今天的内容,.....,就想看前一天的内容了”;
3、可以用另一个线程去强行关闭正在拉数据的连接,无非就是拉数据的线程会抛异常而已了;
4、如果能善用KeepAlive的话,可以减少创建新连接的时间开销;
5、如果能的话,适当合并所需拉取的文件数,比如把本来需要多次调用并得到多个JSON的合并为一次调用就可以得到一组JSON;当然这个需要你有修改服务端的能力才行。


谢谢你的建议,不过对我来说都不是太容易的事。。。。
1、线程池没听说过
2、缓存的话没问题
3、用另一个线程去关闭拉数据的线程,意思就是加一个boolean开关呗?但是下载图片都是用的一个线程,开关打开了第二个下载会不会直接就中断了?
4、也没听说过。。。。。
5、没能力,json的开销很小,主要还是图片,除非用自己的服务器去拉图片,感觉有点太小题大做了

再次感谢你的建议!!~

#4


引用 1 楼 xmt1139057136 的回复:
你是想一个一个的下载,还是将要下载的文件打包zip文件后在下载


打包zip的我看过了,不过还要自己写服务端,暂时没能力啊

#5


引用 3 楼 Walkline 的回复:
谢谢你的建议,不过对我来说都不是太容易的事。。。。


有挑战才有进步。

1、线程池没听说过
—— 这个不算太难吧,Google下应该大把样例;
2、缓存的话没问题
—— 缓存也分内存还是磁盘,要设计好;而且缓存有个清理机制问题
3、用另一个线程去关闭拉数据的线程,意思就是加一个boolean开关呗?但是下载图片都是用的一个线程,开关打开了第二个下载会不会直接就中断了?
—— 不是简单加个开关而已,是直接对该线程所持有的Socket执行close,然后对线程执行interrupt;当然你可以都写在一个函数中。
4、也没听说过。。。。。
—— HTTP协议的其中一个能力,要求服务器在资源下载完毕后不自动关闭连接,Client端可继续申请下一个资源下载。
5、没能力,json的开销很小,主要还是图片,除非用自己的服务器去拉图片,感觉有点太小题大做了
—— 取决于需求。互联网上很多网站的优化甚至包括多张小图片合并为一张大图片等,都是为了减少交互次数。最大可能减少交互次数一般被认为是高性能页面设计的核心目标之一。
—— 你可以自己在局域网上做个实验看看,同样是10G的文件,直接Copy一个10G的单个文件,与Copy10G分成100万个小文件,你可以感性认识下性能差异如何。

#6


该回复于2014-07-06 14:16:47被管理员删除

#7


该回复于2014-07-06 15:41:21被管理员删除

#8


该回复于2014-07-06 15:38:39被管理员删除

#9


该回复于2014-07-06 15:41:36被管理员删除

#10


引用 5 楼 ldh911 的回复:
Quote: 引用 3 楼 Walkline 的回复:

谢谢你的建议,不过对我来说都不是太容易的事。。。。


有挑战才有进步。

1、线程池没听说过
—— 这个不算太难吧,Google下应该大把样例;
2、缓存的话没问题
—— 缓存也分内存还是磁盘,要设计好;而且缓存有个清理机制问题
3、用另一个线程去关闭拉数据的线程,意思就是加一个boolean开关呗?但是下载图片都是用的一个线程,开关打开了第二个下载会不会直接就中断了?
—— 不是简单加个开关而已,是直接对该线程所持有的Socket执行close,然后对线程执行interrupt;当然你可以都写在一个函数中。
4、也没听说过。。。。。
—— HTTP协议的其中一个能力,要求服务器在资源下载完毕后不自动关闭连接,Client端可继续申请下一个资源下载。
5、没能力,json的开销很小,主要还是图片,除非用自己的服务器去拉图片,感觉有点太小题大做了
—— 取决于需求。互联网上很多网站的优化甚至包括多张小图片合并为一张大图片等,都是为了减少交互次数。最大可能减少交互次数一般被认为是高性能页面设计的核心目标之一。
—— 你可以自己在局域网上做个实验看看,同样是10G的文件,直接Copy一个10G的单个文件,与Copy10G分成100万个小文件,你可以感性认识下性能差异如何。


谢谢你的耐心回复,太感动了 求教批量下载文件的思路

1、搜了下ThreadPool,貌似是java1.5以后才开始正式支持,我用的是1.3,不过在ibm的网页上找到 一篇文章,修改之后可用,不过有点小问题每次execute之后需要中断一下才能下载,否则只下载第一个,明天调试一下应该能找到问题

2、存储缓存的话可选数据库,等到以后有需要时再说了,我现在用的是byte数组存在类里

3、结合第一条里的代码,是用vector存储runnable的,如果要清除的话,只要清空vector就可以了,最多是等正在下载的那个进程结束而已,这样也是一个不错的方法,哈哈~

4、你这么说的话我就明白KeepAlive是什么了,以前用到过,见笑了。。。。。。这个我也考虑了,新建一个全局的http connection传递KeepAlive参数,然后在Thread Pool里循环调用下载,for结束后再关闭连接,这样应该会节省不少连接的开销了

5、最后这个试验就不用做了,地球人都知道结果的。。。。。

再次感谢你的答复,受益匪浅啊!!~

#11


引用 2 楼 ldh911 的回复:
两个建议:
1、用线程池来拉数据,避免随意开线程;
2、适当缓存已拉下来的数据,特别合适于解决你这种:“我刚刚打开了今天的内容,.....,就想看前一天的内容了”;
3、可以用另一个线程去强行关闭正在拉数据的连接,无非就是拉数据的线程会抛异常而已了;
4、如果能善用KeepAlive的话,可以减少创建新连接的时间开销;
5、如果能的话,适当合并所需拉取的文件数,比如把本来需要多次调用并得到多个JSON的合并为一次调用就可以得到一组JSON;当然这个需要你有修改服务端的能力才行。

分析的好,赞

#12


引用 5 楼 ldh911 的回复:
Quote: 引用 3 楼 Walkline 的回复:

谢谢你的建议,不过对我来说都不是太容易的事。。。。


有挑战才有进步。

1、线程池没听说过
—— 这个不算太难吧,Google下应该大把样例;
2、缓存的话没问题
—— 缓存也分内存还是磁盘,要设计好;而且缓存有个清理机制问题
3、用另一个线程去关闭拉数据的线程,意思就是加一个boolean开关呗?但是下载图片都是用的一个线程,开关打开了第二个下载会不会直接就中断了?
—— 不是简单加个开关而已,是直接对该线程所持有的Socket执行close,然后对线程执行interrupt;当然你可以都写在一个函数中。
4、也没听说过。。。。。
—— HTTP协议的其中一个能力,要求服务器在资源下载完毕后不自动关闭连接,Client端可继续申请下一个资源下载。
5、没能力,json的开销很小,主要还是图片,除非用自己的服务器去拉图片,感觉有点太小题大做了
—— 取决于需求。互联网上很多网站的优化甚至包括多张小图片合并为一张大图片等,都是为了减少交互次数。最大可能减少交互次数一般被认为是高性能页面设计的核心目标之一。
—— 你可以自己在局域网上做个实验看看,同样是10G的文件,直接Copy一个10G的单个文件,与Copy10G分成100万个小文件,你可以感性认识下性能差异如何。


测试成功了!!!!!~

线程池只开2个线程下载速度也很快了,http connection加了KeepAlive没有close动作确实节省不少时间,要结束前一个下载也不用强行关闭连接,只要删除所有runnable,等待正在下载的那个自动结束就可以了

不过还是太过频繁的下载,压力测试才几下设备就自动重启了。。。。。所以目前只能规规矩矩的使用,效果还是很不错的,谢谢你了!~

#13


好吧。。。等结贴了来看。。。

#14


看了下,建议对我们这些新手来说很有用,多谢分享!

#15


多谢了,这对我们这些新手来说很有意义

#1


你是想一个一个的下载,还是将要下载的文件打包zip文件后在下载

#2


两个建议:
1、用线程池来拉数据,避免随意开线程;
2、适当缓存已拉下来的数据,特别合适于解决你这种:“我刚刚打开了今天的内容,.....,就想看前一天的内容了”;
3、可以用另一个线程去强行关闭正在拉数据的连接,无非就是拉数据的线程会抛异常而已了;
4、如果能善用KeepAlive的话,可以减少创建新连接的时间开销;
5、如果能的话,适当合并所需拉取的文件数,比如把本来需要多次调用并得到多个JSON的合并为一次调用就可以得到一组JSON;当然这个需要你有修改服务端的能力才行。

#3


引用 2 楼 ldh911 的回复:
两个建议:
1、用线程池来拉数据,避免随意开线程;
2、适当缓存已拉下来的数据,特别合适于解决你这种:“我刚刚打开了今天的内容,.....,就想看前一天的内容了”;
3、可以用另一个线程去强行关闭正在拉数据的连接,无非就是拉数据的线程会抛异常而已了;
4、如果能善用KeepAlive的话,可以减少创建新连接的时间开销;
5、如果能的话,适当合并所需拉取的文件数,比如把本来需要多次调用并得到多个JSON的合并为一次调用就可以得到一组JSON;当然这个需要你有修改服务端的能力才行。


谢谢你的建议,不过对我来说都不是太容易的事。。。。
1、线程池没听说过
2、缓存的话没问题
3、用另一个线程去关闭拉数据的线程,意思就是加一个boolean开关呗?但是下载图片都是用的一个线程,开关打开了第二个下载会不会直接就中断了?
4、也没听说过。。。。。
5、没能力,json的开销很小,主要还是图片,除非用自己的服务器去拉图片,感觉有点太小题大做了

再次感谢你的建议!!~

#4


引用 1 楼 xmt1139057136 的回复:
你是想一个一个的下载,还是将要下载的文件打包zip文件后在下载


打包zip的我看过了,不过还要自己写服务端,暂时没能力啊

#5


引用 3 楼 Walkline 的回复:
谢谢你的建议,不过对我来说都不是太容易的事。。。。


有挑战才有进步。

1、线程池没听说过
—— 这个不算太难吧,Google下应该大把样例;
2、缓存的话没问题
—— 缓存也分内存还是磁盘,要设计好;而且缓存有个清理机制问题
3、用另一个线程去关闭拉数据的线程,意思就是加一个boolean开关呗?但是下载图片都是用的一个线程,开关打开了第二个下载会不会直接就中断了?
—— 不是简单加个开关而已,是直接对该线程所持有的Socket执行close,然后对线程执行interrupt;当然你可以都写在一个函数中。
4、也没听说过。。。。。
—— HTTP协议的其中一个能力,要求服务器在资源下载完毕后不自动关闭连接,Client端可继续申请下一个资源下载。
5、没能力,json的开销很小,主要还是图片,除非用自己的服务器去拉图片,感觉有点太小题大做了
—— 取决于需求。互联网上很多网站的优化甚至包括多张小图片合并为一张大图片等,都是为了减少交互次数。最大可能减少交互次数一般被认为是高性能页面设计的核心目标之一。
—— 你可以自己在局域网上做个实验看看,同样是10G的文件,直接Copy一个10G的单个文件,与Copy10G分成100万个小文件,你可以感性认识下性能差异如何。

#6


该回复于2014-07-06 14:16:47被管理员删除

#7


该回复于2014-07-06 15:41:21被管理员删除

#8


该回复于2014-07-06 15:38:39被管理员删除

#9


该回复于2014-07-06 15:41:36被管理员删除

#10


引用 5 楼 ldh911 的回复:
Quote: 引用 3 楼 Walkline 的回复:

谢谢你的建议,不过对我来说都不是太容易的事。。。。


有挑战才有进步。

1、线程池没听说过
—— 这个不算太难吧,Google下应该大把样例;
2、缓存的话没问题
—— 缓存也分内存还是磁盘,要设计好;而且缓存有个清理机制问题
3、用另一个线程去关闭拉数据的线程,意思就是加一个boolean开关呗?但是下载图片都是用的一个线程,开关打开了第二个下载会不会直接就中断了?
—— 不是简单加个开关而已,是直接对该线程所持有的Socket执行close,然后对线程执行interrupt;当然你可以都写在一个函数中。
4、也没听说过。。。。。
—— HTTP协议的其中一个能力,要求服务器在资源下载完毕后不自动关闭连接,Client端可继续申请下一个资源下载。
5、没能力,json的开销很小,主要还是图片,除非用自己的服务器去拉图片,感觉有点太小题大做了
—— 取决于需求。互联网上很多网站的优化甚至包括多张小图片合并为一张大图片等,都是为了减少交互次数。最大可能减少交互次数一般被认为是高性能页面设计的核心目标之一。
—— 你可以自己在局域网上做个实验看看,同样是10G的文件,直接Copy一个10G的单个文件,与Copy10G分成100万个小文件,你可以感性认识下性能差异如何。


谢谢你的耐心回复,太感动了 求教批量下载文件的思路

1、搜了下ThreadPool,貌似是java1.5以后才开始正式支持,我用的是1.3,不过在ibm的网页上找到 一篇文章,修改之后可用,不过有点小问题每次execute之后需要中断一下才能下载,否则只下载第一个,明天调试一下应该能找到问题

2、存储缓存的话可选数据库,等到以后有需要时再说了,我现在用的是byte数组存在类里

3、结合第一条里的代码,是用vector存储runnable的,如果要清除的话,只要清空vector就可以了,最多是等正在下载的那个进程结束而已,这样也是一个不错的方法,哈哈~

4、你这么说的话我就明白KeepAlive是什么了,以前用到过,见笑了。。。。。。这个我也考虑了,新建一个全局的http connection传递KeepAlive参数,然后在Thread Pool里循环调用下载,for结束后再关闭连接,这样应该会节省不少连接的开销了

5、最后这个试验就不用做了,地球人都知道结果的。。。。。

再次感谢你的答复,受益匪浅啊!!~

#11


引用 2 楼 ldh911 的回复:
两个建议:
1、用线程池来拉数据,避免随意开线程;
2、适当缓存已拉下来的数据,特别合适于解决你这种:“我刚刚打开了今天的内容,.....,就想看前一天的内容了”;
3、可以用另一个线程去强行关闭正在拉数据的连接,无非就是拉数据的线程会抛异常而已了;
4、如果能善用KeepAlive的话,可以减少创建新连接的时间开销;
5、如果能的话,适当合并所需拉取的文件数,比如把本来需要多次调用并得到多个JSON的合并为一次调用就可以得到一组JSON;当然这个需要你有修改服务端的能力才行。

分析的好,赞

#12


引用 5 楼 ldh911 的回复:
Quote: 引用 3 楼 Walkline 的回复:

谢谢你的建议,不过对我来说都不是太容易的事。。。。


有挑战才有进步。

1、线程池没听说过
—— 这个不算太难吧,Google下应该大把样例;
2、缓存的话没问题
—— 缓存也分内存还是磁盘,要设计好;而且缓存有个清理机制问题
3、用另一个线程去关闭拉数据的线程,意思就是加一个boolean开关呗?但是下载图片都是用的一个线程,开关打开了第二个下载会不会直接就中断了?
—— 不是简单加个开关而已,是直接对该线程所持有的Socket执行close,然后对线程执行interrupt;当然你可以都写在一个函数中。
4、也没听说过。。。。。
—— HTTP协议的其中一个能力,要求服务器在资源下载完毕后不自动关闭连接,Client端可继续申请下一个资源下载。
5、没能力,json的开销很小,主要还是图片,除非用自己的服务器去拉图片,感觉有点太小题大做了
—— 取决于需求。互联网上很多网站的优化甚至包括多张小图片合并为一张大图片等,都是为了减少交互次数。最大可能减少交互次数一般被认为是高性能页面设计的核心目标之一。
—— 你可以自己在局域网上做个实验看看,同样是10G的文件,直接Copy一个10G的单个文件,与Copy10G分成100万个小文件,你可以感性认识下性能差异如何。


测试成功了!!!!!~

线程池只开2个线程下载速度也很快了,http connection加了KeepAlive没有close动作确实节省不少时间,要结束前一个下载也不用强行关闭连接,只要删除所有runnable,等待正在下载的那个自动结束就可以了

不过还是太过频繁的下载,压力测试才几下设备就自动重启了。。。。。所以目前只能规规矩矩的使用,效果还是很不错的,谢谢你了!~

#13


好吧。。。等结贴了来看。。。

#14


看了下,建议对我们这些新手来说很有用,多谢分享!

#15


多谢了,这对我们这些新手来说很有意义