java 文件下载 并发_多线程并发下载同一文件DEMO | 学步园

该代码示例展示了如何使用Java实现多线程下载大文件,通过HttpURLConnection连接并设置范围请求来分块下载,同时利用CountDownLatch进行同步控制,确保所有线程完成后再继续执行。
摘要由CSDN通过智能技术生成

DownloadFile.java

import java.io.BufferedInputStream;

import java.io.BufferedReader;

import java.io.File;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.net.HttpURLConnection;

import java.net.URL;

public class DownloadFile {

private File file;

private String url;

private int startPos;

private int endPos;

private int totalSize;

private String fileName;

public File getFile() {

return file;

}

public void setFile(File file) {

this.file = file;

}

public String getUrl() {

return url;

}

public void setUrl(String url) {

this.url = url;

}

public int getStartPos() {

return startPos;

}

public void setStartPos(int startPos) {

this.startPos = startPos;

}

public int getEndPos() {

return endPos;

}

public void setEndPos(int endPos) {

this.endPos = endPos;

}

public int getTotalSize() {

return totalSize;

}

public void setTotalSize(int totalSize) {

this.totalSize = totalSize;

}

public String getFileName() {

return fileName;

}

public void setFileName(String fileName) {

this.fileName = fileName;

}

public int getURLTotalSize() throws Exception{

int total = 0;

if(this.url != null && !"".equals(this.url)){

URL url = new URL(this.url);

HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();

return httpConn.getContentLength();

}

return total;

}

public InputStream getInputStream(){

InputStream is = null;

try{

if(this.url != null && !"".equals(this.url)){

URL url = new URL(this.url);

HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();

httpConn.setRequestProperty("Connection", "Keep-Alive"); //保持一直连接

httpConn.setConnectTimeout(60 * 1000 * 5); //连接超时5分钟

httpConn.setRequestMethod("POST"); //以GET方式连接

httpConn.setAllowUserInteraction(true);

if(this.startPos != 0 || this.endPos != 0){

httpConn.setRequestProperty("Range", "bytes=" + getStartPos() + "-" + getEndPos());

}

return new BufferedInputStream(httpConn.getInputStream(),1024*8);

}

}catch(Exception ex){

ex.printStackTrace();

}

return is;

}

public static void main(String[] args) throws Exception {

DownloadFile downloadFile = new DownloadFile();

downloadFile.setUrl("http://localhost:8080/navigater/admin/123.txt");

downloadFile.setStartPos(5);

downloadFile.setEndPos(880);

InputStream is = downloadFile.getInputStream();

System.out.println("is------>" +is.available());

BufferedReader br = new BufferedReader(new InputStreamReader(is));

String str = null;

while(null != (str = br.readLine())){

System.out.println(str);

}

}

}

Test.java

import java.io.BufferedInputStream;

import java.io.File;

import java.io.InputStream;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class Test {

public static void main(String[] args) throws Exception {

/*InputStream file = new FileInputStream("c:" + File.separator + "123.txt");

byte[] by = new byte[5];

System.out.println(file.markSupported());

//file.mark(1);

//file.reset();

file.skip(5);

int length = file.read(by,0,5);

System.out.println(length);

System.out.println(new String(by));*/

Test test = new Test();

test.saveFile();

}

public void saveFile() throws Exception{

File file = new File("c:" + File.separator + "456.exe");

if(file.exists())file.delete();

//RandomAccessFile randomFile = new RandomAccessFile(file,"rwd");

URL url = new URL("http://localhost:8080/navigater/admin/MyEclipse_6.5.0GA_E3.3.2_Installer_A.exe");

HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();

int totalSize = httpConn.getContentLength();

System.out.println("totalSize---------->" + totalSize);

int threadNum = (int)Math.ceil(totalSize/(1024*800f));

System.out.println("threadNum---------->" + threadNum);

CountDownLatch threadCount = new CountDownLatch (threadNum);

ExecutorService service = Executors.newFixedThreadPool(4);

for(int i=0; i

RandomAccessFile randomFile = new RandomAccessFile(file,"rwd");

DownloadFile downloadFile = new DownloadFile();

downloadFile.setUrl("http://localhost:8080/navigater/admin/MyEclipse_6.5.0GA_E3.3.2_Installer_A.exe");

downloadFile.setStartPos(i*1024*800);

int ends = (i+1)*1024*800-1;

if(ends

downloadFile.setEndPos(ends);

}else{

downloadFile.setEndPos(totalSize-1);

}

downloadFile.setTotalSize(totalSize);

randomFile.seek(downloadFile.getStartPos());

service.execute(new MyThread(randomFile,downloadFile, threadCount));

}

threadCount.await();

//randomFile.close();

service.shutdown();

System.out.println("全部完成");

}

class MyThread implements Runnable{

private RandomAccessFile randomFile;

private DownloadFile downloadFile;

private CountDownLatch threadCount;

public MyThread() {

}

public MyThread(RandomAccessFile randomFile, DownloadFile downloadFile, CountDownLatch threadCount) {

this.randomFile = randomFile;

this.downloadFile = downloadFile;

this.threadCount = threadCount;

}

@Override

public void run() {

try{

InputStream is = this.downloadFile.getInputStream();

byte[] by = new byte[1024*40];

int length = 0;

//ByteArrayOutputStream baos = new ByteArrayOutputStream();

while(-1 != (length = is.read(by, 0, by.length))){

//this.randomFile.seek(this.downloadFile.getStartPos());

this.randomFile.write(by,0,length);

//baos.write(by,0,length);

}

//System.out.println(this.downloadFile.getStartPos()+ "~~~~~~~~~~~~~~~~~" + this.downloadFile.getEndPos()+ "~~~~~~~~~~~~~~~~~" + new String(baos.toByteArray()));

is.close();

threadCount.countDown();

}catch(Exception ex){

ex.printStackTrace();

}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.得到服务器下载文件的大小,然后在本地设置一个临时文件和服务器端文件大小一致 a)获得访问网络地址 b)通过URL对象的openConnection()方法打开连接,返回一个连接对象 c)设置请求头 i.setRequestMethod ii.setConnectTimeout iii.setReadTimeout d)判断是否响应成功 e)获取文件长度(getContentLength()) f)随机访问文件的读取与写入RandomAccessFile(file, mode) g)设置临时文件与服务器文件大小一致(setLength()) h)关闭临时文件 2.计算出每个线程下载的大小(开始位置,结束位置) a)计算出每个线程下载的大小 b)for循环,计算出每个线程的开始、结束位置 c)最后一个线程处理 3.每创建好一次就要开启线程下载 a)构造方法 b)通过URL对象的openConnection()方法打开连接,返回一个连接对象 c)设置请求头 i.setRequestMethod ii.setConnectTimeout d)判断是否响应成功(206) e)获取每个线程返回的流对象 f)随机访问文件的读取与写入RandomAccessFile(file, mode) g)指定开始位置 h)循环读取 i.保存每个线程下载位置 ii.记录每次下载位置 iii.关闭临时记录位置文件 iv.随机本地文件写入 v.记录已下载大小 i)关闭临时文件 j)关闭输入流 4.为了杀死线程还能继续下载的情况下,从本地文件上读取已经下载文件的开始位置 a)创建保存记录结束位置的文件 b)读取文件 c)将流转换为字符 d)获取记录位置 e)把记录位置赋给开始位置 5.当你的n个线程都下载完毕的时候我进行删除记录下载位置的缓存文件 a)线程下载完就减去 b)当没有正在运行的线程时切文件存在时删除文件
第1节你真的了解并发吗? [免费观看][免费观看] 00:27:48分钟 | 第2节理解多线程并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的方式案例演示(一)带返回值的方式00:17:12分钟 | 第8节多种创建线程的方式案例演示(二)使用线程池00:15:40分钟 | 第9节Spring对并发的支持:Spring的异步任务00:11:10分钟 | 第10节使用jdk8提供的lambda进行并行计算00:14:22分钟 | 第11节了解多线程所带来的安全风险00:13:16分钟 | 第12节从线程的优先级看饥饿问题00:18:42分钟 | 第13节从Java字节码的角度看线程安全性问题00:25:43分钟 | 第14节sy nchronized保证线程安全的原理(理论层面)00:13:59分钟 | 第15节synchronized保证线程安全的原理(jvm层面)00:25:03分钟 | 第16节单例问题与线程安全性深入解析00:27:15分钟 | 第17节理解自旋锁,死锁与重入锁00:24:58分钟 | 第18节深入理解volatile原理与使用00:28:30分钟 | 第19节JDK5提供的原子类的操作以及实现原理00:27:10分钟 | 第20节Lock接口认识与使用00:19:54分钟 | 第21节手动实现一个可重入锁00:26:31分钟 | 第22节AbstractQueuedSynchronizer(AQS)详解00:49:04分钟 | 第23节使用AQS重写自己的锁00:31:04分钟 | 第24节重入锁原理与演示00:12:24分钟 | 第25节读写锁认识与原理00:18:04分钟 | 第26节细读ReentrantReadWriteLock源码00:30:38分钟 | 第27节ReentrantReadWriteLock锁降级详解00:13:32分钟 | 第28节线程安全性问题简单总结00:15:34分钟 | 第29节线程之间的通信之wait/notify00:32:12分钟 | 第30节通过生产者消费者模型理解等待唤醒机制00:20:50分钟 | 第31节Condition的使用及原理解析00:17:40分钟 | 第32节使用Condition重写wait/notify案例并实现一个有界队列00:22:05分钟 | 第33节深入解析Condition源码00:21:15分钟 | 第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析00:10:17分钟 | 第36节ThreadLocal 使用及实现原理00:17:41分钟 | 第37节并发工具类CountDownLatch详解00:22:04分钟 | 第38节并发工具类CyclicBarrier 详解00:11:52分钟 | 第39节并发工具类Semaphore详解00:17:27分钟 | 第40节并发工具类Exchanger详解00:13:47分钟 | 第41节CountDownLatch,CyclicBarrier,Semaphore源码解析00:29:57分钟 | 第42节提前完成任务之FutureTask使用00:11:43分钟 | 第43节Future设计模式实现(实现类似于JDK提供的Future)00:19:20分钟 | 第44节Future源码解读00:29:22分钟 | 第45节Fork/Join框架详解00:28:09分钟 | 第46节同步容器与并发容器00:18:44分钟 | 第47节并发容器CopyOnWriteArrayList原理与使用00:15:52分钟 | 第48节并发容器ConcurrentLinkedQueue原理与使用00:31:03分钟 | 第49节Java中的阻塞队列原理与使用00:26:18分钟 | 第50节实战:简单实现消息队列00:11:07分钟 | 第51节并发容器ConcurrentHashMap原理与使用00:38:22分钟 | 第52节线程池的原理与使用00:42:49分钟 | 第53节Executor框架详解00:36:54分钟 | 第54节实战:简易web服务器(一)00:55:34分钟 | 第55节实战:简易web服务器(二)00:24:36分钟 | 第56节JDK8的新增原子操作类LongAddr原理与使用00:17:45分钟 | 第57节JDK8新增锁StampedLock详解00:29:37分钟 | 第58节重排序问题00:23:19分钟 | 第59节happens-before简单概述00:15:17分钟 | 第60节锁的内存语义00:13:54分钟 | 第61节volatile内存语义00:12:04分钟 | 第62节final域的内存语义00:34:07分钟 | 第63节实战:问题定位00:07:48分钟 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值