- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章PC版与Android手机版带断点续传的多线程下载由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
1、多线程下载 。
多线程下载就是抢占服务器资源 。
原理:服务器CPU 分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服务器资源.
1、设置开启线程数,发送http请求到下载地址,获取下载文件的总长度 然后创建一个长度一致的临时文件,避免下载到一半存储空间不够了,并计算每个线程下载多少数据 2、计算每个线程下载数据的开始和结束位置 再次发送请求,用 Range 头请求开始位置和结束位置的数据 3、将下载到的数据,存放至临时文件中 4、带断点续传的多线程下载 。
定义一个int变量,记录每条线程下载的数据总长度,然后加上该线程的下载开始位置,得到的结果就是下次下载时,该线程的开始位置,把得到的结果存入缓存文件,当文件下载完成,删除临时进度文件.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
public
class
MultiDownload {
static
int
ThreadCount = ;
static
int
finishedThread = ;
//确定下载地址
static
String filename =
"EditPlus.exe"
;
static
String path =
"http://...:/"
+filename;
public
static
void
main(String[] args) {
//、发送get请求,去获得下载文件的长度
try
{
URL url =
new
URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(
"GET"
);
conn.setConnectTimeout();
conn.setReadTimeout();
if
(conn.getResponseCode()==) {
//如果请求成功,拿到所请求资源文件的长度
int
length = conn.getContentLength();
//、生成一个与原文件同样的大小的临时文件,以免下载一半存储空间不够了
File file =
new
File(filename);
//演示,所以将保存的文件目录放在工程的同目录
//使用RandomAccessFile 生成临时文件,可以用指针定位文件的任意位置,
//而且能够实时写到硬件底层设备,略过缓存,这对下载文件是突然断电等意外是有好处的
RandomAccessFile raf =
new
RandomAccessFile(file,
"rwd"
);
//rwd, 实时写到底层设备
//设置临时文件的大小
raf.setLength(length);
raf.close();
//、计算出每个线程应该下载多少个字节
int
size = length/ThreadCount;
//如果有余数,负责最后一部分的线程负责下砸
//开启多线程
for
(
int
threadId = ; threadId < ThreadCount; threadId++) {
//计算每个线程下载的开始位置和结束位置
int
startIndex = threadId*size;
// 开始 = 线程id * size
int
endIndex = (threadId+)*size - ;
//结束 = (线程id + )*size -
//如果是最后一个线程,那么结束位置写死为文件结束位置
if
(threadId == ThreadCount - ) {
endIndex = length - ;
}
//System.out.println("线程"+threadId+"的下载区间是: "+startIndex+"----"+endIndex);
new
DownloadThread(startIndex,endIndex,threadId).start();
}
}
}
catch
(MalformedURLException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
class
DownloadThread extends Thread{
private
int
startIndex;
private
int
endIndex;
private
int
threadId;
public
DownloadThread(
int
startIndex,
int
endIndex,
int
threadId) {
super();
this
.startIndex = startIndex;
this
.endIndex = endIndex;
this
.threadId = threadId;
}
public
void
run() {
//每个线程再次发送http请求,下载自己对应的那部分数据
try
{
File progressFile =
new
File(threadId+
".txt"
);
//判断进度文件是否存在,如果存在,则接着断点继续下载,如果不存在,则从头下载
if
(progressFile.exists()) {
FileInputStream fis =
new
FileInputStream(progressFile);
BufferedReader br =
new
BufferedReader(
new
InputStreamReader(fis));
//从进度文件中度取出上一次下载的总进度,然后与原本的开始进度相加,得到新的开始进度
startIndex += Integer.parseInt(br.readLine());
fis.close();
}
System.
out
.println(
"线程"
+threadId+
"的下载区间是:"
+startIndex+
"----"
+endIndex);
//、每个线程发送http请求自己的数据
URL url =
new
URL(MultiDownload.path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(
"GET"
);
conn.setConnectTimeout();
conn.setReadTimeout();
//设置本次http请求所请求的数据的区间
conn.setRequestProperty(
"Range"
,
"bytes="
+startIndex+
"-"
+endIndex);
//请求部分数据,响应码是
if
(conn.getResponseCode()==) {
//此时,流里只有ThreadCount分之一的原文件数据
InputStream
is
= conn.getInputStream();
byte
[] b =
new
byte
[];
int
len = ;
int
total = ;
//total 用于保存断点续传的断点
//拿到临时文件的输出流
File file =
new
File(MultiDownload.filename);
RandomAccessFile raf =
new
RandomAccessFile(file,
"rwd"
);
//把文件的写入位置移动至 startIndex
raf.seek(startIndex);
while
((len =
is
.read(b))!=-) {
//每次读取流里数据之后,同步把数据写入临时文件
raf.write(b, , len);
total += len;
//System.out.println("线程" + threadId + "下载了" + total);
//生成一个一个专门用来记录下载进度的临时文件
RandomAccessFile progressRaf =
new
RandomAccessFile(progressFile,
"rwd"
);
progressRaf.write((total+
""
).getBytes());
progressRaf.close();
}
System.
out
.println(
"线程"
+threadId+
"下载完了---------------------"
);
raf.close();
//当所有的线程下载完之后,将进度文件删除
MultiDownload.finishedThread++;
synchronized (MultiDownload.path) {
//所有线程使用同一个锁
if
(MultiDownload.finishedThread==MultiDownload.ThreadCount) {
for
(
int
i = ; i < MultiDownload.ThreadCount; i++) {
File f =
new
File(i+
".txt"
);
f.delete();
}
MultiDownload.finishedThread=;
}
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
|
2、Android手机版带断点续传的多线程下载 。
Android手机版的带断点续传的多线程下载逻辑与PC版的几乎一样,只不过在Android手机中耗时操作不能放在主线程,网络下载属于耗时操作,所以多线程下载要在Android中开启一个子线程执行。并使用消息队列机制刷新文本进度条.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
public
class
MainActivity extends Activity {
static
int
ThreadCount = ;
static
int
FinishedThread = ;
int
currentProgess;
static
String Filename =
"QQPlayer.exe"
;
static
String Path =
"http://...:/"
+Filename;
static
MainActivity ma;
static
ProgressBar pb;
static
TextView tv;
static
Handler handler =
new
Handler(){
public
void
handleMessage(android.os.Message msg){
tv.setText((
long
)pb.getProgress()* /pb.getMax() +
"%"
);
};
};
protected
void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ma =
this
;
pb = (ProgressBar) findViewById(R.id.pb);
tv = (TextView) findViewById(R.id.tv);
}
public
void
download(View v){
Thread t =
new
Thread(){
public
void
run() {
//发送http请求获取文件的长度,创建临时文件
try
{
URL url=
new
URL(Path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(
"GET"
);
conn.setConnectTimeout();
conn.setReadTimeout();
if
(conn.getResponseCode()==) {
int
length = conn.getContentLength();
//设置进度条的最大值就是原文件的总长度
pb.setMax(length);
//生成一个与原文件相同大小的临时文件
File file =
new
File(Environment.getExternalStorageDirectory(),Filename);
RandomAccessFile raf =
new
RandomAccessFile(file,
"rwd"
);
raf.setLength(length);
raf.close();
//计算每个线程需要下载的数据大小
int
size = length/ThreadCount;
//开启多线程
for
(
int
threadId = ; threadId < ThreadCount; threadId++) {
int
startIndex = threadId*size;
int
endIndex = (threadId + )*size - ;
if
(threadId==ThreadCount - ) {
endIndex = length - ;
}
new
DownloadThread(startIndex, endIndex, threadId).start();
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
};
t.start();
}
class
DownloadThread extends Thread{
private
int
startIndex;
private
int
endIndex;
private
int
threadId;
public
DownloadThread(
int
startIndex,
int
endIndex,
int
threadId) {
super();
this
.startIndex = startIndex;
this
.endIndex = endIndex;
this
.threadId = threadId;
}
public
void
run() {
// 每个线程发送http请求自己的数据
try
{
//先判断是不是断点续传
File progessFile =
new
File(Environment.getExternalStorageDirectory(),threadId+
".txt"
);
if
(progessFile.exists()) {
FileReader fr =
new
FileReader(progessFile);
BufferedReader br =
new
BufferedReader(fr);
int
lastProgess = Integer.parseInt(br.readLine());
startIndex += lastProgess;
//把上次下载的进度显示至进度条
currentProgess +=lastProgess;
pb.setProgress(currentProgess);
//发消息,让主线程刷新文本进度
handler.sendEmptyMessage();
br.close();
fr.close();
}
URL url =
new
URL(Path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(
"GET"
);
conn.setConnectTimeout();
conn.setReadTimeout();
conn.setRequestProperty(
"Range"
,
"bytes="
+startIndex+
"-"
+endIndex);
if
(conn.getResponseCode()==) {
InputStream
is
= conn.getInputStream();
byte
[] buffer =
new
byte
[];
int
len = ;
int
total = ;
File file =
new
File(Environment.getExternalStorageDirectory(),Filename);
RandomAccessFile raf =
new
RandomAccessFile(file,
"rwd"
);
raf.seek(startIndex);
while
((len =
is
.read(buffer))!= -) {
raf.write(buffer, , len);
total += len;
//每次读取流里数据之后,把本次读取的数据的长度显示至进度条
currentProgess += len;
pb.setProgress(currentProgess);
//发消息,让主线程刷新文本进度
handler.sendEmptyMessage();
//生成临时文件保存下载进度,用于断点续传,在所有线程现在完毕后删除临时文件
RandomAccessFile progressRaf =
new
RandomAccessFile(progessFile,
"rwd"
);
progressRaf.write((total+
""
).getBytes());
progressRaf.close();
}
raf.close();
System.
out
.println(
"线程"
+threadId+
"下载完了"
);
//当所有线程都下在完了之后,删除临时进度文件
FinishedThread++;
synchronized (Path) {
if
(FinishedThread==ThreadCount) {
for
(
int
i = ; i < ThreadCount; i++) {
File f =
new
File(Environment.getExternalStorageDirectory(),i+
".txt"
);
f.delete();
}
FinishedThread=;
}
}
}
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
}
|
以上内容是小编跟大家分享的PC版与Android手机版带断点续传的多线程下载,希望大家喜欢.
最后此篇关于PC版与Android手机版带断点续传的多线程下载的文章就讲到这里了,如果你想了解更多关于PC版与Android手机版带断点续传的多线程下载的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
当我的测试用例挂起时,我设法生成了线程转储。但是,这似乎不是死锁、竞争条件或资源争用。但是在我的加载测试工具中使用 3 个虚拟用户运行测试用例时,它肯定会挂起。任何人都可以在这里指出我正确的方向吗?干
复制代码 代码如下: #!/usr/bin/perl use File::DirWalk; use File::Basename; use Data::Dumper; use warnings;
个人认为影响的原因: 匹配到的图片url并不是有效的url,文中只是简单的判断是否是相对路径,但是有些url是失效的 解决办法:就是新增判断是否是真实有效url的图片 复制代码
考虑到这个问题:Passing a Shapeless Extensible Record to a Function,Travis的答案表明,每个以可扩展记录为参数的函数都必须有一个隐式选择器作为参
我通过这样的套接字发送ascii: outputStreamWriter(s + (char) 13); outputStreamWriter.flush(); 在现场,flush() 和通过网络发送
在我们正在进行的重构练习中,我们必须更改选定网站的页面模板。大多数页面都被本地化并通过下面的代码更新了他们的页面模板,但对于一些我们得到以下错误: “名称、文件名对于以下类型的项目必须是唯一的:其结构
我知道已经有Default value on generic predicate as argument了。 但是,也许现在c++ 11,c++ 14或c++ 17有了新的选择? 我如何才能使这项工作
select sum(case when NumFirstNames <> 1 then 1 else 0 end) as DifferentFirstNames, sum(case when
我已将:根证书、中间证书、服务器证书导入 Tomcat for Windows 的 Java Keystore。 这些是 VeriSign(商业)证书.. 我们不能将 keyAlias 用于连接器 -
我的问题是基于这个问题:Correct way to inherit from a virtual class with non-virtual parent . 我的理解是否正确,在问题中描述的情况
我不确定是否需要使用像 PLINQ 这样的高级技术,因为我想重新表述我之前的问题 Paralleling trading software我认为我之前的问题太复杂而且不清楚,我希望现在我准确地提取了所
这是我在这里遇到的问题(仍未解决)的延续:link 但这可能有助于理解问题所在。我只创建了一个简单的测试项目('Empty Application')并添加了一个带有 XIB 文件的 View Con
好的,所以昨天我发布了一个关于创建一个模拟电影矩阵雨的 java jframe 的问题,我希望它就像这个 php 示例一样 http://mgccl.com/2007/03/30/simple-ver
从这个线程继续: What are good algorithms for vehicle license plate detection? 我开发了我的图像处理技术来尽可能强调车牌,总体而言我很满意
这个问题在我这里的问题上继续(根据 Mystical 的建议): C code loop performance 继续我的问题,当我使用打包指令而不是标量指令时,使用内部函数的代码看起来非常相似: f
这是 My Old Question 的延续 这是我创建一个新学生对象的函数: function student(id, name, marks, mob, home){ this.id =
建立在我的 last question我想弄清楚如何.local和 .comm指令准确地工作,特别是它们如何影响 C 中的链接和持续时间。 所以我进行了以下实验: static int value;
这个问题引用这个之前的one由 Christian Metzler 在 SO 上发布. 我唯一非常有限的关于注解的经验包括使用最近 Delphi 版本中引入的 CustomAttribute。 我的问
我正在使用 Jetty 和 Continuations 来实现长轮询,但我没有找到检测客户端断开连接的方法。 我知道,在第一次运行(创建 Continuation)和任何后续运行之间的时间里,由于 H
这是 CSS Display an Image Resized and Cropped 的延续.该用户的答案似乎没问题,但我需要一些帮助来改进该答案... 问:resize(缩放)如何在运行时与图像的
我是一名优秀的程序员,十分优秀!