多线程下载

多线程下载的实现:

1、首先获取文件的长度。

2、设置线程的个数

3、根据长度和线程个数计算每一个线程需要下载的长度。

例如:3个线程下载一个为length=10个字节的文件

int bolckSize=length/3;

则每一部分需要下载的大小为:

线程  1   :int start=0*blockSize     int end=1*blockSize-1;

线程  2   :int start=1*blockSize     int end=2*blockSize-1;

线程  3   :int start=2*blockSize     int end=length-1;//到最后

4、根据RandomAccessFile  raf 创建一个同样大小的空文件。

5、设置Http请求的头信息

connection.setRequestProperty("range", "bytes=" + start + "-" + end);

6、根据raf.seek(int length),把下载好的数据写入空文件的指定位置,拼接成完整的文件。

实现:

用Tomcat作为服务器,服务器目录C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\ROOT下放置了一个guanguan.apk文件。

主界面就一个Button按钮。

public class MainActivity extends Activity implements View.OnClickListener {
    //    要下载文件的路径
    private String urlPath = "http://localhost:8080/guanguan.apk";
    private String filePath;
    //    设置线程的数目。
    private int threadCount = 3;
    private Button mButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.button);
        mButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.button) {
            Log.d("dd","开始下载");
            new Thread(new GetDataFromNet()).start();
        }
    }
//访问网络的类:
    private class GetDataFromNet implements Runnable {
        @Override
        public void run() {
            try {
		//请求网络
                URL url = new URL(urlPath);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(5000);
		//  获取返回值
                int code = connection.getResponseCode();
                if (code == 200) {
		// 获取数据总长度
                    int length = connection.getContentLength();
                    Log.d("dd","文件长度"+length);
		//  设置下载位置
                    filePath = "/sdcard" + "/guanguan.apk";
                  File file = new File(filePath);
                  Log.d("dd", "下载路径:" + filePath);

		//    通过RandomAccessFile创建一个空文件。   rwd  文件权限信息
                  RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
		//     设置空文件的大小
                  accessFile.setLength(length);
                  accessFile.close();
		//每一段的大小
                  int bolckSize = length / threadCount;
	//计算每个线程下载的起始位置。
                  for(int i = 0; i < threadCount; i++) {
                      int start = i * bolckSize;
                      int end = (i + 1) * bolckSize - 1;
		//如果是最后一个线程,则结束位置为文件的末尾
                      if (i == (threadCount - 1)) {
                          end = length-1;
                        }
                        Log.d("dd", "第" + i + "个线程" + "从" + start + "到" + end);
                        new DownloadFile(urlPath, filePath, start, end).start();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
//文件下载类
public class DownloadFile extends Thread {
    private String urlPath;//下载路径
    private String fileName;//文件保存路径
    private int start;//开始位置
    private int end;//结束位置
//构造方法
    public DownloadFile(String urlPath, String fileName, int start, int end) {
        this.urlPath = urlPath;
        this.fileName = fileName;
        this.start = start;
        this.end = end;
    }
    @Override
    public void run() {
        URL url = null;
        try {
            url = new URL(urlPath);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000);
//   设置Http头的信息,即要指明获取的是那一段数据。
            connection.setRequestProperty("range", "bytes=" + start + "-" + end);

            int code = connection.getResponseCode();
//注意部分下载返回的code值为  206
            if (code == 206) {
                InputStream is = connection.getInputStream();
                File file = new File(fileName);
//创建RandomAccessFile,要与上次已经创建文件名以及权限一致
                RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
//该方法用来操作建造好的空文件,可以指明从文件的那个位置开始写入
                accessFile.seek(start);
                byte[] buf = new byte[1024];
                int len = 0;
                while ((len = is.read(buf)) >0) {
                    accessFile.write(buf, 0, len);
                }
                is.close();
                accessFile.close();
                Log.d("dd", "该线程下载了" + start + "--" + end);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果:



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值