Java реализует многопоточную загрузку файла браузера

Описание заголовка запроса браузера

Диапазон заголовка HTTP-запроса

请求资源的部分内容(不包括响应头的大小),单位是byte,即字节,从0开始.
如果服务器能够正常响应的话,服务器会返回 206 Partial Content 的状态码及说明.
如果不能处理这种Range的话,就会返回整个资源以及响应状态码为 200 OK .
(这个要注意,要分段下载时,要先判断这个)

Формат заголовка запроса диапазона

Range: bytes=start-end
Range: bytes=10- :第10个字节及最后个字节的数据
Range: bytes=40-100 :第40个字节到第100个字节之间的数据.

Описание заголовка ответа

Content-Range: bytes 0-10/3103 //这个表示,服务器响应了前(0-10)个字节的数据,该资源一共有(3103)个字节大小。
Content-Type: image/png   //表示这个资源的类型
Content-Length: 11  //表示这次服务器响应了11个字节的数据(0-10)
Last-Modified: Tue, 30 Jun 2015 03:12:48 GMT  //表示资源最近修改的时间(分段下载时要注意这个东西,因为如果修改了,分段下载可能就要重新下载了)
ETag: W/"3103-1435633968000"  //这个响应头表示资源版本的标识符,通常是消息摘要(类似MD5一样)

Первый шаг — получить размер загружаемого файла.

private static long getFileSize() {
    
    
        HttpURLConnection connection = null;
        HttpURLConnection conn = null;
        try {
    
    
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setConnectTimeout(3000);
            conn.setRequestMethod("HEAD");
            conn.connect();
            String headerField = conn.getHeaderField("Content-Disposition");
            System.out.println("Content-Disposition:" + headerField);
            String eTag = conn.getHeaderField("ETag");
            System.out.println("ETag:" + eTag);
            String contentType = conn.getContentType();
            System.out.println("contentType:" + contentType);
            System.out.println("* 连接服务器成功");
        } catch (MalformedURLException e) {
    
    
            throw new RuntimeException("URL错误");
        } catch (IOException e) {
    
    
            System.err.println("x 连接服务器失败[" + e.getMessage() + "]");
            return -1;
        }
        return conn.getContentLengthLong();
    }

Второй шаг - вычислить данные, которые будут загружены каждым потоком в соответствии с потоком.

  private static String url = "http://a.xzfile.com/down4/bitcometv1.71_downcc.com.zip";
    //www.downcc.com  解压密码

    private static int  thnum=5;


    public static void main(String[] args) throws IOException {
    
    
        //
        File f = new File(getFileName());
        boolean newFile = f.createNewFile();
        RandomAccessFile rw = new RandomAccessFile(f.getName(), "rw");
        FileChannel channel = rw.getChannel();
        long fileSize = getFileSize();
        //channel.write(ByteBuffer.allocate(0), 1);
        System.out.println("文件大小:"+fileSize);
        System.out.println(f.getAbsolutePath());
        System.out.println(f.getCanonicalPath());
        //f.renameTo(new File("D:\\java\\gsProject\\torrent\\com.zip"+"downloadTemp"));
       //ReName(f.getAbsolutePath(),"temp.zz");
       int c = (int) (fileSize/thnum);
        for (int i = 0; i <thnum ; i++) {
    
    
            int begin = i*c;
            int end =begin+c;
            if(i == (thnum-1)){
    
    
                end = (int) fileSize;
            }
            MyDownloadTask myDownloadTask = new MyDownloadTask(url,getFileName(),(int)fileSize,begin,end);
            Thread t = new Thread(myDownloadTask);
            t.start();
        }
      //  MyDownloadTask myDownloadTask = new MyDownloadTask(url,getFileName(),(int)fileSize);
       // myDownloadTask.run();
    }

Третий шаг — загрузить все данные, которые необходимо загрузить каждому потоку.

public class MyDownloadTask implements Runnable {
    
    
    //请求下载都url
    private String url;
    //
    private final RandomAccessFile file;
    //文件操作类
    private final FileChannel channel; // 线程安全类
    private int begin;
    private int end;

    private int pageSize;

    public MyDownloadTask(String url, String fileName, int pageSize,int begin ,int end) throws FileNotFoundException {
    
    
        this.url = url;
        this.file = new RandomAccessFile(fileName, "rw");
        this.channel = file.getChannel();
        this.pageSize = pageSize;
        this.begin=begin;
        this.end=end;

    }


    @SneakyThrows
    @Override
    public void run() {
    
    
     /*   ReadableByteChannel connect = connect();
        int byteread = 0;
        long lowerBound;
        System.out.println("强转数据"+pageSize);
        ByteBuffer buffer = ByteBuffer.allocate(pageSize); // 2MB
        System.out.println("开始下载-------------------");
        //while ((byteread = connect.read(buffer)) != -1) {
        buffer.clear();
        System.out.println("数据读了多长:"+connect.read(buffer));
        System.out.println("下载中-- 当前文件大小:"+channel.size());
             channel.write(buffer,0);
            System.out.println("下载中-- 当前文件大小:"+channel.size());
            channel.close();
        // }
        System.out.println("下载结束-------------------");*/
        InputStream connect = connect();
        byte [] bytes = new byte[1024];
        int read ;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((read=connect.read(bytes))!=-1){
    
    
            bos.write(bytes,0,read);
        }
        ByteBuffer wrap = ByteBuffer.wrap(bos.toByteArray());
        channel.write(wrap,begin);
        System.out.println(Thread.currentThread().getName()+":下载完成");

    }

    /**
     * 连接WEB服务器,并返回一个数据通道
     *
     * @return 返回通道
     * @throws IOException 网络连接错误
     */
    private InputStream connect() throws IOException {
    
    
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setConnectTimeout(300000);
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Range", "bytes=" + begin+ "-"+end);
        conn.connect();
        int statusCode = conn.getResponseCode();
        if (HttpURLConnection.HTTP_PARTIAL != statusCode) {
    
    
            conn.disconnect();
            throw new IOException("状态码错误:" + statusCode);
        }
        System.out.println(Thread.currentThread().getName()+"服务器响应字节:" + conn.getHeaderField("Content-Length"));
     /*   InputStream inputStream = conn.getInputStream();
        int i;
        int a = 0;
        while ((i = inputStream.read()) != -1) {
            a++;
        }
        System.out.println("返回字节数据:{}"+a);*/
      //  return Channels.newChannel(conn.getInputStream());
        return conn.getInputStream();

    }

}

Acho que você gosta

Origin blog.csdn.net/qq_39164154/article/details/109209953
Recomendado
Clasificación