网络多线线程下载并合并文件示例

package com.yanshu.tread;


import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;


import com.yanshu.io.test.FileUtils;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;
/**
 * 网络多线线程下载并合并文件示例
 * @author Administrator
 *本示例的采用IO流与多线程下载同一张图片,下载完后进行合并;
 *使用方法内创建线程方式,控制主线程的执行时机,即主线程调用方法,
 *方法内创建线程,再返回调用方法的对象,随即往下执行其他程序,
 *可有效防止主线程的其他方法在下载线程(即其他线程)未完成时执行,而出现数据错位缺失。
 */
public class MultithreadedDownload {
public static void main(String[] args) throws Exception {
//主线程采用调用模式创建其他线程,可让其他线程执行完后才继续执行主线中的其他方法,此方式可控制主线的执行时机
String path="https://06.imgmini.eastday.com/mobile/20180315/20180315214247_3de286324ba113ab9d92563c44e0efc1_1.jpeg";
String destPath="E:/Users/Shared/abc";
multithreadedDownloads(path, destPath, 3);
}
/**
* 多线程下合并文件 ,仅适用于Http协议,未尝试其他网络协议
* @param srcPath 下载源文件路径名
* @param destPath 保存文件夹路径名
* @param count 指定线程个数
* @throws Exception 
*/
public static  void multithreadedDownloads(String srcPath,String destPath,int count) throws Exception
{
//1.定义一个下载的文件夹
File file=new File(destPath);
if(!file.exists())
{
file.mkdirs();
}
//2.开始访问需要下载的URL 
long total = getFileLength(srcPath);
//开启下载线程
OpenMultithreadedDownload(srcPath, file, total, count);
//获取文件的后缀名称
String substring = srcPath.substring(srcPath.lastIndexOf("."));
System.out.println("获取文件的后缀名:"+substring);

ExecutorService executorService=Executors.newFixedThreadPool(2);
//JDK1.8 实现异步操作
//JDK1.8 实现异步操作
CompletableFuture<String> future=CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
return "异步结束";

}
},executorService);
//采用lambada的实现方式  
future.thenAccept(e -> System.out.println(e + " ok"));  

Thread.sleep(1000);
//合并名称
merg(file, substring);
System.out.println ("文件下载完成");

}
/**
* 获取文件大小
* @param path 下载源文件路径名
* @return
* @throws Exception 
*/
public static long getFileLength(String path) throws Exception
{
System.out.println("获得下载源文件的路径:"+path);
//下载源文件路径名
URL url=new URL(path);
System.out.println("url:"+url);
//获得连接对象
URLConnection connection=url.openConnection();
System.out.println("打开连接对象:"+connection);
connection.setRequestProperty("Accept-Encoding", "identity");
long total=connection.getContentLength();//当getContentLength();返回时-1或者是0时候 
//解决办法:需加上conn.setRequestProperty("Accept-Encoding", "identity");
System.out.println("total:"+total);
return total;
}
/**
* 多线程下载块
* @param path 下载源文件路径名
* @param dir 目标文件存储目录
* @param total 下载源文件的大小
* @param count 指定线程的数
*/
private static void OpenMultithreadedDownload(String path,File dir,long total, int count)
{
System.out.println("获取图片的大小:"+total);
System.out.println("获取线程的个数:"+count);
//计算出每个线程平均现在的字节个数
long size=total/count;
System.out.println("计算的个数:"+size);
//使用循环,计算每个线程下载的开始和结束位置
for(int i=1;i<=count;i++)
{
//开始位置
long startIndex=(i-1)*size;
System.out.println("开始的位置:"+startIndex);
//结束位置
long endIndex=i*size-1;
System.out.println("结束的位置:"+endIndex);
//最后一个线程
if(i==count)
{
System.out.println("最后一个线程是--->"+i);
endIndex=total-1;
System.out.println("endIndex--->"+endIndex);
}

DownloadThread downloadThread=new DownloadThread(path, dir, startIndex, endIndex, i);
downloadThread.start();
}

}

/**
* //合并文件功能
* @param file  源文件存储的父目录
* @param suffix
* @throws FileNotFoundException 
*/
public static void merg(File dir,String suffix) throws Exception
{

System.out.println("dir----->>>"+dir);
File [] files=dir.listFiles (getFileFilter(suffix,false));
System.out.println("files---->>>"+files.length);
FileOutputStream fos = getFileOutputStream (dir, files[0]);
for(File file : files){
FileInputStream fis = new FileInputStream (file);
int len;
byte[] buf = new byte[8192];
while ((len=fis.read (buf)) != -1){
fos.write (buf,0,len);
}
fis.close ();
//把已经合并过的文件删除
file.delete ();

}
fos.close ();
}
////获取合并文件输出流
private static FileOutputStream getFileOutputStream(File dir, File file) throws FileNotFoundException 
{
File file1 = file;
String name = file1.getName ();
name = name.substring (1);
File destFile = new File (dir,name);
return new FileOutputStream (destFile);
}
/**
* 文件过滤器
* @param suffix  文件后缀名
* @param containDirectory 是否显示子文件夹文件,true为显示,false不显示
* @return
*/
public static FileFilter getFileFilter(String suffix,boolean containDirectory) {
return new FileFilter () {


//断言
@Override
public boolean accept(File file) {
// TODO 自动生成的方法存根
String name = file.getName ();
boolean destFormat = file.isFile()&& name.endsWith(suffix);
boolean b;
b = containDirectory && file.isDirectory ();
if (destFormat || b) return true;
else return false;
}

};
}


}
//下载线程代码
class DownloadThread extends Thread {
private String path;//下载源文件路径名
private  File dir;//目标文件存储目录
private  long startIndex;//线程的开始位置
private  long endIndex;//结束位置
private  int threadID;//指定线程个数
//使用构造方法传入参数
public DownloadThread(String path, File dir, long startIndex,long endIndex, int threadID) {
// TODO 自动生成的构造函数存根
this.path=path;
this.dir=dir;
this.startIndex=startIndex;
this.endIndex=endIndex;
this.threadID=threadID;
}
@Override
public void run() {
// TODO 自动生成的方法存根
try {
InputStream inputStream=getInputStream();
FileOutputStream fileOutputStream = fileOutputStream();
int len;
byte[] arr=new byte[8192];
while((len=inputStream.read(arr))!=-1)
{
fileOutputStream.write(arr, 0, len);
}
inputStream.close();
fileOutputStream.close();
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
//获取下载的输入流
private InputStream getInputStream() throws Exception
{
//创建一个URL对象 
URL url=new URL(path);
System.out.println("url里面的路径:"+url);
//获取到连接对象
URLConnection connection=url.openConnection();
connection.setRequestProperty ("Range","bytes="+startIndex+"-"+endIndex);
//获取到输入流
System.out.println("获取连接对象:"+connection.getInputStream());
return connection.getInputStream();
}
//获取下载输出流
private FileOutputStream fileOutputStream() throws Exception
{
//获取到文件的名字
int index=path.lastIndexOf("/")+1;
System.out.println("获取文件的名字:"+index);
String name=path.substring(index);
System.out.println("截取的名字:"+name);
File file=new File(dir,threadID+name);//创建目标文件键,防止文件覆盖
System.out.println("创建目标文件键,防止文件覆盖-->>"+file);
//创建一个输出流
return new FileOutputStream(file);

}



}

猜你喜欢

转载自blog.csdn.net/ruiguang21/article/details/79580307