`
i2534
  • 浏览: 183547 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

多线程下载

    博客分类:
  • util
阅读更多

这个是下载的工具类,改编自网上找到的annegu兄的代码,这位仁兄是多线程断点,但是我这里不需要断点,所以做了简化。

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 *
 */
public class DownloadUtil {

    private static final Log log = LogFactory.getLog(DownloadUtil.class);
    private int threadNum = 5;
    private String urlStr;
    private File file = null;
    private AtomicBoolean statusError = new AtomicBoolean(false);
    private long sleepSeconds = 5;

    public DownloadUtil(String url, File file, int threadNum) {
        this(url, file, threadNum, 5);
    }

    public DownloadUtil(String url, File file, int threadNum, long sleepSec) {
        this.urlStr = url;
        this.file = file;
        if (threadNum > 0) {
            this.threadNum = threadNum;
        }
        if (sleepSec > 0) {
            this.sleepSeconds = sleepSec;
        }
    }

    public boolean download() {
        log.info("download the file " + file.getName() + " from " + urlStr);
        CountDownLatch latch = new CountDownLatch(threadNum);//这个是亮点
        try {
            file.createNewFile();
            HttpURLConnection con = (HttpURLConnection) new URL(urlStr).openConnection();
            setHeader(con);//这里是伪造头信息
            long contentLength = con.getContentLength();
            long threadLength = contentLength / threadNum;
            ExecutorService exec = Executors.newCachedThreadPool();
            for (int i = 0; i < threadNum; i++) {
                long end = threadLength * (i + 1) - 1;
                if (i == threadNum - 1) {
                    end = contentLength;
                }
                ChildThread thread = new ChildThread(this, latch, i,
                        threadLength * i, end);
                exec.execute(thread);
            }
            try {
                latch.await();
                exec.shutdown();
                if (file.length() != contentLength) {
                    log.warn("file download failed,because the size is not correct");
                    return false;
                }
                return true;
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    private class ChildThread implements Runnable {

        private DownloadUtil task;
        private int id;
        private long startPosition;
        private long endPosition;
        private final CountDownLatch latch;
        private RandomAccessFile file = null;

        public ChildThread(DownloadUtil task, CountDownLatch latch, int id,
                long startPos, long endPos) {
            super();
            this.task = task;
            this.id = id;
            this.startPosition = startPos;
            this.endPosition = endPos;
            this.latch = latch;
            try {
                file = new RandomAccessFile(task.file, "rw");
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }

        public void run() {
            log.info("Thread " + id + " run ...");
            HttpURLConnection con = null;
            InputStream inputStream = null;
            for (;;) {
                try {
                    con = (HttpURLConnection) new URL(task.urlStr).openConnection();
                    setHeader(con);
                    // 设置连接超时时间为10000ms
                    con.setConnectTimeout(10000);
                    // 设置读取数据超时时间为10000ms
                    con.setReadTimeout(10000);

                    if (startPosition < endPosition) {
                        // 设置下载数据的起止区间
                        con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);
                        log.debug("Thread " + id + " startPosition is " + startPosition + ", and endPosition is " + endPosition);

                        file.seek(startPosition);

                        // 判断http status是否为HTTP/1.1 206 Partial Content或者200 OK
                        // 如果不是以上两种状态,把status改为STATUS_HTTPSTATUS_ERROR
                        if (con.getResponseCode() != HttpURLConnection.HTTP_OK && con.getResponseCode() != HttpURLConnection.HTTP_PARTIAL) {
                            log.info("Thread " + id + ": code = " + con.getResponseCode() + ", status = " + con.getResponseMessage());
                            task.statusError.set(true);
                            file.close();
                            con.disconnect();
                            log.info("Thread " + id + " finished.");
                            latch.countDown();
                            break;
                        }

                        inputStream = con.getInputStream();
                        int len = 0;
                        byte[] b = new byte[1024];
                        while (!task.statusError.get() && (len = inputStream.read(b)) != -1) {
                            file.write(b, 0, len);
                            startPosition += len;
                        }

                        file.close();
                        inputStream.close();
                        con.disconnect();
                    }

                    log.info("Thread " + id + " finished.");
                    latch.countDown();
                    break;
                } catch (IOException ex) {
//                    log.error(ex.getMessage(), ex);
                    try {
                        TimeUnit.SECONDS.sleep(task.sleepSeconds);
                    } catch (InterruptedException e) {
                        log.error(e.getMessage(), e);
                    }
                    continue;
                }
            }
        }
    }

    private void setHeader(URLConnection con) {
        con.setRequestProperty(
                "User-Agent",
                "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3");
        con.setRequestProperty("Accept-Language", "en-us,en;q=0.7,zh-cn;q=0.3");
//        con.setRequestProperty("Accept-Encoding", "aa");
        con.setRequestProperty("Accept-Charset",
                "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
        con.setRequestProperty("Keep-Alive", "300");
        con.setRequestProperty("Connection", "keep-alive");
        con.setRequestProperty("If-Modified-Since",
                "Fri, 02 Jan 2009 17:00:05 GMT");
        con.setRequestProperty("If-None-Match", "\"1261d8-4290-df64d224\"");
        con.setRequestProperty("Cache-Control", "max-age=0");
//        con.setRequestProperty("Referer",
//                "http://www.skycn.com/soft/14857.html");
    }
}
 
分享到:
评论

相关推荐

    C#实现支持断点续传多线程下载客户端工具类

    多线程下载则能显著提高大文件下载的速度,通过将文件分割成多个部分并同时下载来利用多核处理器的优势。 这个C# DIY HttpWebClient工具类基于对System.Net.WebClient的修改和扩展。WebClient是.NET Framework提供...

    C# Winform 多线程下载

    在C# Winform应用中实现多线程下载是一项常见的任务,尤其在处理大文件或需要提高下载速度的情况下。本文将详细讲解如何利用C#的多线程技术来创建一个Winform应用程序,实现高效的文件下载功能。 首先,我们需要...

    易语言多线程下载不卡速度快

    在本项目中,“易语言多线程下载不卡速度快”是一个利用易语言实现的多线程下载工具,旨在提供高效、稳定的文件下载体验。通过多线程技术,该工具能够同时处理多个下载链接,使得下载过程更加流畅,减少因单一线程...

    利用idhttp进行多线程下载

    在Delphi编程环境中,利用 Indy (Internet Direct) 的 `TIdHTTP` 组件进行多线程下载是一项常见的任务,尤其适用于处理大文件,以提高下载效率并提供更好的用户体验。`TIdHTTP` 是Indy库中的一个核心组件,用于执行...

    C#实现多线程下载文件

    本文将深入探讨如何在C#中实现多线程下载文件,涉及的知识点包括线程池、异步编程、进度更新以及错误处理。 首先,我们需要了解线程的基本概念。在C#中,线程是程序执行的独立路径,每个线程都有自己的调用堆栈,...

    多线程下载器.zip易语言项目例子源码下载

    《多线程下载器——易语言项目实例解析》 在当今高速发展的互联网世界中,高效的数据传输成为了一项重要的需求。多线程下载器作为提升下载速度的有效工具,被广泛应用于各种场景。本文将深入剖析一个基于易语言实现...

    C#模仿迅雷的多线程下载类

    ### C#模仿迅雷的多线程下载类:深度解析与应用 在现代软件开发中,网络资源的高效下载已成为一个关键环节。特别是在处理大文件或在网络条件不佳的情况下,单线程下载往往效率低下,用户体验差。为此,多线程下载...

    多线程下载+进度条

    在IT领域,多线程下载和进度条显示是提高用户体验和优化下载效率的重要技术。这里我们将深入探讨这两个概念以及如何实现它们。 首先,多线程下载是指在一个下载任务中使用多个独立的线程同时从服务器获取数据。这种...

    SpringBoot版本的多线程下载文件,分段下载文件

    本篇将深入探讨如何利用SpringBoot实现多线程下载文件以及分段下载文件的技术。 首先,多线程下载文件是一种提高下载速度的方法,通过将大文件分成多个小部分,每个部分由一个单独的线程负责下载,从而充分利用多核...

    C# httpwebrequest 多线程下载类

    在多线程下载场景中,我们通常会为每个下载任务创建一个独立的线程,以便并发执行多个请求,提高下载效率。 下面,我们将逐步解析实现`C# httpwebrequest 多线程下载类`的关键步骤: 1. **创建下载类**:首先,...

    多线程下载工具

    标题中的“多线程下载工具”指的是一个利用多线程技术来提高文件下载速度的应用程序。在计算机编程中,多线程是指在一个程序内同时执行多个独立的线程,每个线程负责不同的任务,比如在下载场景中,一个线程负责处理...

    基于Qt5和libcurl的多线程下载器.zip

    【标题】基于Qt5和libcurl的多线程下载器是一种高效的C++应用程序,它利用了Qt5的图形用户界面(GUI)库和libcurl库的功能来实现文件的多线程下载。Qt5是一个功能丰富的跨平台应用开发框架,支持Windows、Linux、...

    多线程下载原理

    在IT领域,多线程下载是一项重要的技术,尤其在处理大文件或大量数据时,能够显著提高下载效率。本文将详细解析"多线程下载原理",并结合提供的java工程net和android工程videonews来深入理解这一概念。 首先,我们...

    易语言多线程下载源码

    在“易语言多线程下载源码”这个主题中,我们将深入探讨如何使用易语言实现高效的多线程下载功能。 在互联网上下载大文件时,单线程下载往往速度受限,而多线程下载可以显著提高下载效率,因为它允许同时从服务器...

    android断点续传_多线程下载demo

    在Android开发中,断点续传和多线程下载是提高用户下载体验的重要技术。本文将深入探讨如何在Android客户端实现这些功能,并结合服务器端的配合来完成整个流程。 首先,断点续传(Resumable Download)允许用户在...

    python m3u8多线程下载器

    在本项目中,我们关注的是利用Python实现的“m3u8多线程下载器”。M3U8是一种基于HTTP/HTTPS协议的流媒体格式,常用于在线视频播放,尤其在移动设备上。它将视频文件分割成多个小片段,方便流式传输。 这个下载器...

    多线程下载demo

    在IT领域,多线程下载是一种常见的优化网络资源获取的技术,尤其在大文件下载时能够显著提高下载速度。本文将详细解析多线程下载的原理、实现方式以及断点续传的概念。 首先,多线程下载的核心思想是将一个大的文件...

    安卓retrofit2 + rxjava2 + okhttp3多线程下载

    在Android开发中,实现多线程下载是一项常见的需求,尤其对于大文件来说,单线程下载不仅速度慢,用户体验也较差。本项目标题提到的"安卓retrofit2 + rxjava2 + okhttp3多线程下载"正是一个利用现代Android开发库来...

    Java多线程下载器

    Java多线程下载器是一种利用Java编程语言实现的高效文件下载工具,它通过将大文件分割成多个部分并同时下载,显著提高了下载速度。在Java中实现多线程下载器涉及许多关键概念和技术,包括线程、并发控制、网络I/O...

Global site tag (gtag.js) - Google Analytics