java 多线程 文件下载_Java多线程文件下载

一. 多线程下载文件考虑处理步骤:

1. 如何获取文件的长度

2. 合理的创建线程数量,并计算每一个线程下载的长度

3. 如何将多个线程下载的字节写入到文件中

二. 代码实现如下:

package com.bochao.download;

import java.io.File;

import java.net.URL;

import java.net.URLConnection;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

/**

* HTTP多线程下载

*

* @Author DuanCZ

* @Date 2015年9月30日-上午9:28:28

*/

public class HttpMulitThreadDownload {

// 下载文件路径

private String downloadFilePath = null;

// 保存文件路径

private String saveFileDir = "c:\\";

// 默认合理并发线程数

private int threadCount = Runtime.getRuntime().availableProcessors() * 2;

// 新文件名称

private String newFileName = null;

public HttpMulitThreadDownload(int threadCount, String downloadFilePath, String saveFileDir, String newFileName) {

// 用户指定线程数如果小于默认线程数则使用用户指定线程数

if (threadCount < this.threadCount) {

this.threadCount = threadCount;

}

this.downloadFilePath = downloadFilePath;

this.saveFileDir = saveFileDir;

this.newFileName = newFileName;

}

public void MulitThreadDownload() {

// 数据合法性验证

if (null == downloadFilePath || downloadFilePath.isEmpty()) {

throw new RuntimeException("请指定下载路径!");

}

if (null == saveFileDir || saveFileDir.isEmpty()) {

throw new RuntimeException("请指定保存路径!");

}

// 创建保存文件路径如果不存在

File saveFileDirTemp = new File(saveFileDir);

if (!saveFileDirTemp.exists()) {

saveFileDirTemp.mkdirs();

}

// 处理文件名称

if (null == newFileName || newFileName.isEmpty()) {

newFileName = downloadFilePath.substring(downloadFilePath.lastIndexOf("/") + 1, downloadFilePath.length());

}

// 创建固定大小的线程池

ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);

try {

// 根据文件长度计算合理线程数开始

URLConnection urlConnection = new URL(downloadFilePath).openConnection();

// 获取文件长度

int downloadFileLength = urlConnection.getContentLength();

// 计算每个线程负责的文件字节长度

int averageThreadLength = downloadFileLength / threadCount;

int residueThreadLength = downloadFileLength % threadCount;

// 让每一个线程开始工作

int startIndex = 0;

int endIndex = 0;

for (int i = 0; i < threadCount; i++) {

// 计算每一个线程开始和计数索引

startIndex = i * averageThreadLength;

// 如果是最后一个线程,则将剩余的全部下载

if ((i + 1) == threadCount) {

endIndex = (i + 1) * averageThreadLength + residueThreadLength - 1;

}

endIndex = (i + 1) * averageThreadLength - 1;

// 创建下载线程对象

DownloadHandlerThread downloadHandlerThread = new DownloadHandlerThread();

downloadHandlerThread.setDownloadFilePath(downloadFilePath);

downloadHandlerThread.setSaveFilePath(saveFileDir + newFileName);

downloadHandlerThread.setStartIndex(startIndex);

downloadHandlerThread.setEndIndex(endIndex);

threadPool.execute(downloadHandlerThread);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

// 关闭线程池

threadPool.shutdown();

}

}

}

package com.bochao.download;

import java.io.IOException;

import java.io.InputStream;

import java.io.RandomAccessFile;

import java.net.URL;

import java.net.URLConnection;

import java.text.SimpleDateFormat;

import java.util.Date;

/**

* 下载文件处理线程

*

* @Author DuanCZ

* @Date 2015年9月30日-上午11:38:42

*/

public class DownloadHandlerThread implements Runnable {

// 待下载的HTTP文件路径

private String downloadFilePath = null;

// 下载保存文件路径

private String saveFilePath = null;

// 文件随机写入开始索引

private int startIndex = 0;

// 文件随机写入结束索引

private int endIndex = 0;

@Override

public void run() {

System.out.println("线程名称[" + Thread.currentThread().getName() + "]于时间["

+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "]开始下载....");

// 文件输入流对象

InputStream fileInputStream = null;

// 随机访问文件

RandomAccessFile randomAccessFile = null;

// ------------------------------------------------------------------------------

// 获取随机文件流开始

// 获取一个URL打开链接对象

URLConnection urlConnection = null;

try {

urlConnection = new URL(downloadFilePath).openConnection();

} catch (IOException e1) {

e1.printStackTrace();

}

// 设置该链接允许和用户交互

urlConnection.setAllowUserInteraction(true);

// 设置请求属性字节范围

urlConnection.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex + "");

try {

// 获取指定的文件流

fileInputStream = urlConnection.getInputStream();

} catch (IOException e) {

e.printStackTrace();

}

// ------------------------------------------------------------------------------获取随机文件流结束

// ------------------------------------------------------------------------

// 写文件流到指定的文件开始

try {

// 创建文件随机访问对象

randomAccessFile = new RandomAccessFile(saveFilePath, "rw");

// 将文件写入位置移动到其实点

randomAccessFile.seek(startIndex);

// 写入文件

int bytes = 0;

byte[] buffer = new byte[100 * 1024];

while ((bytes = fileInputStream.read(buffer, 0, buffer.length)) != -1) {

randomAccessFile.write(buffer, 0, bytes);

}

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (null != randomAccessFile) {

randomAccessFile.close();

}

if (null != fileInputStream) {

fileInputStream.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

// ------------------------------------------------------------------------写文件流到指定的文件结束

System.out.println("线程名称[" + Thread.currentThread().getName() + "]于时间["

+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "]下载完成!");

}

public String getDownloadFilePath() {

return downloadFilePath;

}

public void setDownloadFilePath(String downloadFilePath) {

this.downloadFilePath = downloadFilePath;

}

public String getSaveFilePath() {

return saveFilePath;

}

public void setSaveFilePath(String saveFilePath) {

this.saveFilePath = saveFilePath;

}

public int getStartIndex() {

return startIndex;

}

public void setStartIndex(int startIndex) {

this.startIndex = startIndex;

}

public int getEndIndex() {

return endIndex;

}

public void setEndIndex(int endIndex) {

this.endIndex = endIndex;

}

}

测试:

package com.bochao.download;

public class TestDownload {

public static void main(String[] args) {

String downloadFilePath = "http://localhost:81/mulitThreadDownload/file/PowerDesigner165_Evaluation.1428562995.exe";

String saveFileDir= "f:\\Download\\";

HttpMulitThreadDownload httpMulitThreadDownload = new HttpMulitThreadDownload(2, downloadFilePath, saveFileDir, "powerdesigner.exe");

httpMulitThreadDownload.MulitThreadDownload();

}

}

输出结果:

线程名称[pool-1-thread-1]于时间[2015-08-30 16:09:49]开始下载....

线程名称[pool-1-thread-2]于时间[2015-08-30 16:09:49]开始下载....

线程名称[pool-1-thread-2]于时间[2015-09-30 16:09:01]下载完成!

线程名称[pool-1-thread-1]于时间[2015-09-30 16:09:23]下载完成!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值