android多线程断点下载

本文介绍了一种基于Android平台的多线程文件上传技术实现方案。通过将文件分割为多个部分并使用独立线程进行上传,提高了上传效率。文章详细讲解了如何利用HTTP连接、线程同步和文件读写等技术实现断点续传和进度跟踪。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.alleged.manyThreadUpload;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;






import android.support.v7.app.ActionBarActivity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;


public class MainActivity extends ActionBarActivity implements OnClickListener {
private static int threadCount = 0;// 线程数量
private static int blockSize = 0;// 每个线程要下载的大小
private static int runningTrheadCount = 0;// 记录未完成的线程数量
private static String path = "http://192.168.36.77:8567/itheima74/feiq.exe";// 网络请求的地址
private static int StartIndex;
private static int endIndex;
private static int lastIndex;
private Context mcontext;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mcontext=this;
/*第一步:设置布局
布局一个输入框,一个按钮,布局框中让用户数据要开的线程数量
在用户点击按钮后,清除linearview的中的控件,再添加相应数量的滚动条控件(把xml布局文件转化成view类的对象)
*/
/*第二步:与用户交互,取得控件值,执行相应的操作
* */
Button upload = (Button) findViewById(R.id.Thread_submit);
upload.setOnClickListener(this);




}
@Override
public void onClick(View v) {
//获取用户输入的线程数量
EditText th_count = (EditText) findViewById(R.id.ThreadCount);
int thread_count = Integer.parseInt(th_count.getText().toString());
threadCount = thread_count;
//根据线程数,添加相应的progressBar
LinearLayout pro_container = (LinearLayout) findViewById(R.id.progressBar_contaner);
pro_container.removeAllViews();
for(int ThreadId=0;ThreadId<thread_count;ThreadId++){
ProgressBar pro_layout = (ProgressBar) View.inflate(mcontext, R.layout.probar_layout, null);
pro_container.addView(pro_layout);
}
new Thread(new Runnable() {

@Override
public void run() {
DownFile();
}
}).start();
//DownFile();

}
public static String getFileName(String url) {


return Environment.getExternalStorageDirectory()+url.substring(url.lastIndexOf("/"));
}
public void DownFile(){
try {
System.out.println("_________________________");
// 创建一个连接对象
URL url = new URL(path);
// 打开一个连接对象
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// 设置请求头,包括请求方式,请求时间
connection.setRequestMethod("GET");
connection.setConnectTimeout(10 * 1000);
// 得到response相应的状态吗
int code = connection.getResponseCode();
if (code == 200) {
// 得到资源的大小
int fileLength = connection.getContentLength();
// 创建randomAccessFile类,第一参数文件类对象,第二个参数操作文件的权限
System.out.println(getFileName(path));
System.out.println("222222222");
RandomAccessFile randomAccessFile = new RandomAccessFile(
new File(getFileName(path)), "rwd");
// 设置文件的大小,即占位
randomAccessFile.setLength(fileLength);
blockSize = fileLength / threadCount;
// 设置线程的开始位置和结束位置
for (int threadId = 0; threadId < threadCount; threadId++) {
if (threadId != (threadCount - 1)) {
StartIndex = threadId * blockSize;
endIndex = (threadId + 1) * blockSize - 1;
} else {
StartIndex = threadId * blockSize;
endIndex = fileLength-1;
}
System.out.println("下载线程开启");
new DownThread(threadId, StartIndex, endIndex).start();
}
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public class DownThread extends Thread {
private int ThreadID;
private int StartIndex;
private int endIndex;
private int lastIndex;


public DownThread(int ThreadID, int StartIndex, int endIndex) {
this.ThreadID = ThreadID;
this.StartIndex = StartIndex;
this.endIndex = endIndex;
System.out.println("downthread 初始化");
}


@Override
public void run() {
// 文件锁,避免多个线程同时操作一个文件或者变量
synchronized (DownThread.class) {


runningTrheadCount = runningTrheadCount + 1;// 一个新的线程开始,就记录下来
}


try {
URL url = new URL(path);
HttpURLConnection openConnection = (HttpURLConnection) url
.openConnection();
openConnection.setRequestMethod("GET");
openConnection.setConnectTimeout(10 * 1000);
// 查看专属文件存在就读取数据,不存在就创建文件
File file = new File(Environment.getExternalStorageDirectory()+"/"+ThreadID + ".txt");
if (file.exists()) {
// 文件存在,
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream(file)));
lastIndex = Integer.parseInt(bufferedReader.readLine());
StartIndex = lastIndex;
openConnection.setRequestProperty("Range", "bytes:"
+ StartIndex + "-" + endIndex);
System.out.println("线程id:"+ThreadID+"起始位置:"+StartIndex+"结束位置"+endIndex);
bufferedReader.close();
} else {
openConnection.setRequestProperty("Range", "bytes:"
+ StartIndex + "-" + endIndex);
System.out.println("线程id:"+ThreadID+"起始位置:"+StartIndex+"结束位置"+endIndex);
}

//判断请求的状态码,这里需要注意 200是全部资源的请求成功码  206是部分资源请求成功码
if(openConnection.getResponseCode()==206){
//创建一个输入流,用来承接资源的
InputStream in  =  openConnection.getInputStream();
//打开要下载的资源文件
RandomAccessFile randomAccessFile = new RandomAccessFile(new File(getFileName(path)), "rw");
//设置文件指针的位置
randomAccessFile.seek(StartIndex);
//输入流写入文件
//创建一个字节缓冲区
byte[] buffer = new byte[1024];
int length =-1;//保存字节数组的长度
int total = 0;//写入的数据大小
while((length = in.read(buffer))!=-1){
//把buffer写给文件
randomAccessFile.write(buffer, 0, length);
total = total+length;
//如果断点下次线程的起始位置
int currentThreadPosition = StartIndex+total;
//打开线程的专属文件,把文件的起始位置,写入文件
File file1 = new File(Environment.getExternalStorageDirectory()+"/"+ThreadID+".txt");
RandomAccessFile accessfile = new RandomAccessFile(file1, "rwd");
accessfile.write(String.valueOf(currentThreadPosition).getBytes());
accessfile.close();
}
in.close();
randomAccessFile.close();//关闭流
//下载完成,删除专属文件,加锁避免多个线程操作同意一个文件
synchronized (DownThread.class) {
runningTrheadCount = runningTrheadCount -1;//鏍囧織鐫�涓�涓嚎绋嬩笅杞界粨鏉熴��
if(runningTrheadCount == 0 ){
for(int i =0 ;i< threadCount;i++){
File file2 = new File(Environment.getExternalStorageDirectory()+"/"+i+".txt");
System.out.println(file2.getAbsolutePath());
file2.delete();
}
}

}
}
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ProtocolException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值