Java使用io流和多线程实现切割文件,合并文件
原创
©著作权归作者所有:来自51CTO博客作者Emiyas的原创作品,请联系作者获取转载授权,否则将追究法律责任
主体类
package com.file;
import com.sun.glass.ui.Size;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @program: Maven
* @description: 测试2
* @author: hw
* @create: 2018-12-25 00:38
**/
public class Demo2 {
//文件的路径
private String filePath;
//文件名
private String fileName;
//文件大小
private long length;
//块数
private int size;
//每块的大小
private long blockSize;
//分割后的存放目录
private String destBlockPath;
//每块的名称
private List<String> blockPath;
public Demo2() {
blockPath = new ArrayList<String>();
}
public Demo2(String filePath, String destBlockPath) {
this(filePath, destBlockPath, 1024 * 1024 * 100);
}
public Demo2(String filePath, String destBlockPath, long blockSize) {
this();
this.filePath = filePath;
this.destBlockPath = destBlockPath;
this.blockSize = blockSize;
init();
}
/**
* @Description: 初始化操作 计算 块数、确定文件名
* @Param: []
* @return: void
* @Author: hw
* @Date: 2018/12/25
*/
public void init() {
File file = null;
//如果为空或者路径为文件夹则返回
if (filePath == null || !((file = new File(filePath)).exists()) || file.isDirectory())
return;
//文件名
this.fileName = file.getName();
//计算分割数量 实际大小 每块大小
this.length = file.length();
//每块大小
if (this.blockSize > length) {
this.blockSize = length;
}
//确定分割数量
size = (int) Math.ceil(length * 1.0 / this.blockSize);
//确定分割文件的路径
initPathName();
}
private void initPathName() {
for (int i = 0; i < size; i++) {
this.blockPath.add(destBlockPath + "/" + this.fileName + ".part" + i);
}
}
/**
* 文件的分割
* 0)、第几块
* 1、起始位置
* 2、实际大小
* 分割文件存放目录
*/
boolean exeFlag = true;
public void split() {
long beginPos = 0; //起始点
long actualBlockSize = blockSize; //实际大小
//计算所有块的大小、位置、索引
for (int i = 0; i < size; i++) {
if (i == size - 1) { //最后一块
actualBlockSize = length - beginPos;
}
spiltDetail(i, beginPos, actualBlockSize);
//多线程版本
// new Run(i,beginPos,actualBlockSize,filePath,blockPath).start();
beginPos += actualBlockSize; //本次的终点,下一次的起点
}
}
public static void main(String[] args) {
//1024 * 30 表示按照每块30Kb大小分割
final Demo2 split = new Demo2("D:/BaiduNetdiskDownload/123.mp4", "D:/BaiduNetdiskDownload/123/", 1024 * 200 * 1024);
System.out.println(split.size);
long l = System.currentTimeMillis();
split.split();
// split.merge("D:/BaiduNetdiskDownload/123/123.mp4");
}
/**
* @Description: 文件分割
* @Param: [idx, beginPos, actualBlockSize]
* @return: void
* @Author: hw
* @Date: 2018/12/25
*/
private void spiltDetail(int idx, long beginPos, long actualBlockSize) {
//1、创建源
File src = new File(this.filePath); //源文件
File dest = new File(this.blockPath.get(idx)); //目标文件
//2、选择流
RandomAccessFile raf = null; //输入流
BufferedOutputStream bos = null; //输出流
try {
raf = new RandomAccessFile(src, "r");
bos = new BufferedOutputStream(new FileOutputStream(dest));
//读取文件
raf.seek(beginPos);
//缓冲区
byte[] flush = new byte[1024<<2];
//接收长度
int len = 0;
while (-1 != (len = raf.read(flush))) {
if (actualBlockSize - len >= 0) { //查看是否足够
//写出
bos.write(flush, 0, len);
actualBlockSize -= len; //剩余量
} else { //写出最后一次的剩余量
bos.write(flush, 0, (int) actualBlockSize);
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
this.close(bos, raf);
}
}
/**
* 文件的合并
*/
public void merge(String destPath) {
//创建源
File dest = new File(destPath);
//选择流
BufferedOutputStream bos = null; //输出流
SequenceInputStream sis = null;//输入流
//创建一个容器
Vector<InputStream> vi = new Vector<InputStream>();
try {
for (int i = 0; i < this.blockPath.size(); i++) {
vi.add(new BufferedInputStream(new FileInputStream(new File(this.blockPath.get(i)))));
}
bos = new BufferedOutputStream(new FileOutputStream(dest, true)); //追加
sis = new SequenceInputStream(vi.elements());
//缓冲区
byte[] flush = new byte[1024<<2];
//接收长度
int len = 0;
while (-1 != (len = sis.read(flush))) {
bos.write(flush, 0, len);
}
bos.flush();
this.close(sis);
} catch (Exception e) {
} finally {
this.close(bos);
}
}
/关闭流
public static void close(Closeable... io) {
for (Closeable temp : io) {
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}
/**
* 使用泛型方法
*/
public static <T extends Closeable> void closeAll(T... io) {
for (Closeable temp : io) {
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}
}
线程类
package com.file;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;
/**
* @program: Maven
* @description:
* @author: hw
* @create: 2018-12-25 01:20
**/
public class Run extends Thread {
private int i;
private long beginPos;
private long actualBlockSize;
private String filePath;
//每块的名称
private List<String> blockPath;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public long getBeginPos() {
return beginPos;
}
public void setBeginPos(long beginPos) {
this.beginPos = beginPos;
}
public long getActualBlockSize() {
return actualBlockSize;
}
public void setActualBlockSize(long actualBlockSize) {
this.actualBlockSize = actualBlockSize;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public List<String> getBlockPath() {
return blockPath;
}
public void setBlockPath(List<String> blockPath) {
this.blockPath = blockPath;
}
public Run(int i, long beginPos, long actualBlockSize, String filePath, List<String> blockPath) {
this.i = i;
this.beginPos = beginPos;
this.actualBlockSize = actualBlockSize;
this.filePath = filePath;
this.blockPath = blockPath;
}
@Override
public void run() {
System.out.println(1);
//1、创建源
File src = new File(this.filePath); //源文件
File dest = new File(this.blockPath.get(i)); //目标文件
//2、选择流
RandomAccessFile raf = null; //输入流
BufferedOutputStream bos = null; //输出流
try {
raf = new RandomAccessFile(src, "r");
bos = new BufferedOutputStream(new FileOutputStream(dest));
//读取文件
raf.seek(beginPos);
//缓冲区
byte[] flush = new byte[1024<<2];
//接收长度
int len = 0;
while (-1 != (len = raf.read(flush))) {
if (actualBlockSize - len >= 0) { //查看是否足够
//写出
bos.write(flush, 0, len);
actualBlockSize -= len; //剩余量
} else { //写出最后一次的剩余量
bos.write(flush, 0, (int) actualBlockSize);
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
this.close(bos, raf);
System.out.println(2);
}
}
/关闭流
public static void close(Closeable... io) {
for (Closeable temp : io) {
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}
/**
* 使用泛型方法
*/
public static <T extends Closeable> void closeAll(T... io) {
for (Closeable temp : io) {
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}
}
如果电脑磁盘和性能都比较好的话可以试试多线程版本,如不然的话就用单线程的就够了