URL的应用-多线程下载

Uri的四个主要组成部分:

    [scheme:][//authority][path][?query][#fragment]

    scheme:指http、file、content等;

    authority:在ContentProvider中有使用,没有找到对应的中文翻译;

    path:在authority之后的相对路径;

    query:查询语句。

    fragment:主要指id。

举例:

    1. Uri :http://www.google.com/getDetails?id=123

   对应的四部分:

        secheme:http, authority: www.google.com, path : /getDetails, query: id=123

  2,. Uri : content://com.fx.demo:200/system/etc/#28

    对应的四部分:

        secheme:content, authority: com.fx.demo:200, path : /system/etc, query: null, fragment:28

使用URL对象建立连接,获取要下在的文件的大小,然后将文件按照大小均分给4个线程,每个线程下载完分配给自己的那部分,即完成了任务。

涉及的要点:
1. 每个线程使用url.openStream()创建一个InputStream,他们可以相互独立的读取url所指向的文件,同时进行比特流的传输;

2. 下载文件时,指定一个byte[]来缓存临时文件,这个数组不要太大,否则可能出现从流中读不满长度为数组大小的字节。

下面看一看代码:

package com.yxf.uridemos;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;

public class UriDemos {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        final String URL_ADDRESS = "http://images.china-pub.com/ebook3770001-3775000/3770325/ch01.pdf";
        final int DOWNLOAD_THREAD_NUM = 4;
        final String OUT_FILE_NAME = "out_put.pdf";
        
        InputStream[] inputArray = new InputStream[DOWNLOAD_THREAD_NUM];
        RandomAccessFile[] outputArray = new RandomAccessFile[DOWNLOAD_THREAD_NUM];
        
        try {
            URL url = new URL(URL_ADDRESS);
            long fileLength = getFileLength(url);
            long numPerThread = fileLength / DOWNLOAD_THREAD_NUM;
            long left = fileLength % DOWNLOAD_THREAD_NUM;

            for(int i = 0 ; i < DOWNLOAD_THREAD_NUM;i++) {
                inputArray[i] = url.openStream();
                outputArray[i] = new RandomAccessFile(OUT_FILE_NAME, "rw");
                if(i == DOWNLOAD_THREAD_NUM - 1) {
                    new DownloadThread(i * numPerThread, (i + 1) * numPerThread + left, inputArray[i], outputArray[i]).start();
                }else {
                    new DownloadThread(i * numPerThread, (i + 1) * numPerThread, inputArray[i], outputArray[i]).start();
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    private static long getFileLength(URL url) {
        try {
            URLConnection connection = url.openConnection();
            return connection.getContentLength();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return 0;
    }
}

package com.yxf.uridemos;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

public class DownloadThread extends Thread{
    private long start;
    private long end;
    private InputStream inputStream;
    private RandomAccessFile output;
    
    private long count;
    private final int BUF_LEN = 128;
    public DownloadThread(long start, long end, InputStream inputStream, RandomAccessFile output){
        this.start = start;
        this.end = end;
        this.inputStream = inputStream;
        this.output = output;
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            inputStream.skip(start);
            output.seek(start);
            byte[] buff = new byte[BUF_LEN];
            
            long contentLen = end - start;
            long times = contentLen / BUF_LEN + 20;
            int hasRead = 0;
            for(int i = 0; i < times; i++) {
                hasRead = inputStream.read(buff);
                count += hasRead;
                if(hasRead < 0) {
                    break;
                }
                output.write(buff, 0, hasRead);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if(output != null) {
                    output.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值