import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
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.OutputStream;
/**
* 1、实现一个文件分割器,把一个大文件分割成若干个小文件(可根据情况自行设计),
* 分割后的文件扩展名为dat,文件名为:原文件名+原扩展名+编号+.data
* 2、把分割后的文件再合并(文件还原)成完整文件,与源文件一致。
*/
public class FGutil {
/**
* 文件分割
*
* @param src 源文件路径
* @param fileSize 分割后每个文件的大小,单位是MB
* @param dest 目标文件路径
*/
public static void split(String src, int fileSize, String dest) {
System.out.println("分割开始。。。");
if ("".equals(src) || src == null || fileSize == 0 || "".equals(dest) || dest == null) {
System.out.println("分割失败");
}
//源文件
File srcFile = new File(src);
//源文件的大小
long srcSize = srcFile.length();
//目标文件的大小(分割后每个文件的大小)
long destSize = 1024 * 1024 * fileSize;
int number = (int) (srcSize / destSize);
//分割后文件的数目
number = srcSize % destSize == 0 ? number : number + 1;
//源文件名
String fileName = src.substring(src.lastIndexOf("\\"));
//输入字节流
InputStream in = null;
//输入缓冲流
BufferedInputStream bis = null;
//每次读取文件的大小为1MB
byte[] bytes = new byte[1024 * 1024];
//每次读取的长度值
int len = -1;
try (ConsumeTime consumeTime = new ConsumeTime()) {
in = new FileInputStream(srcFile);
bis = new BufferedInputStream(in);
for (int i = 0; i < number; i++) {
String destName = dest + File.separator + fileName + "-" + (i + 1) + ".data";
OutputStream out = new FileOutputStream(destName);
BufferedOutputStream bos = new BufferedOutputStream(out);
int count = 0;
//把字节数据写入目标文件中
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
count += len;
if (count >= destSize) {
break;
}
}
//刷新
bos.flush();
bos.close();
out.close();
}
System.out.println("分割完成");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭流
try {
if (bis != null) {
bis.close();
}
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 文件合并
* 注意:在拼接文件路劲时,一定不要忘记文件的跟路径,否则复制不成功
*
* @param destPath 目标目录
* @param srcPaths 源文件目录
*/
public static void merge(String destPath, String... srcPaths) {
System.out.println("开始合并。。。");
if (destPath == null || "".equals(destPath) || srcPaths == null) {
System.out.println("合并失败");
}
for (String string : srcPaths) {
if ("".equals(string) || string == null) {
System.out.println("合并失败");
}
}
//合并后的文件名
String name = srcPaths[0].substring(srcPaths[0].lastIndexOf("\\"));
String destName = name.substring(0, name.lastIndexOf("-"));
//合并后的文件路径
destPath = destPath + destName;
//合并后的文件
File destFile = new File(destPath);
OutputStream out = null;
BufferedOutputStream bos = null;
try (ConsumeTime consumeTime = new ConsumeTime()) {
out = new FileOutputStream(destFile);
bos = new BufferedOutputStream(out);
for (String src : srcPaths) {
File srcFile = new File(src);
InputStream in = new FileInputStream(srcFile);
BufferedInputStream bis = new BufferedInputStream(in);
byte[] bytes = new byte[1024 * 1024];
int len = -1;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
bis.close();
in.close();
}
System.out.println("合并结束");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭流
try {
if (bos != null) {
bos.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
/**
* 分割测试
*/
//要分割的大文件
String src = "E:\\Spire.Doc.jar";
int fileSize = 5;
//文件分割后保存的路径
String dest = "E:\\fgtest";
split(src, fileSize, dest);
/**
* 合并测试
*/
//合并后文件的保存路径
String destPath = "E:\\hbtest";
//要合并的文件路径
String[] srcPaths = {
"E:\\fgtest\\Spire.Doc.jar-1.data",
"E:\\fgtest\\Spire.Doc.jar-2.data",
"E:\\fgtest\\Spire.Doc.jar-3.data",
"E:\\fgtest\\Spire.Doc.jar-4.data",
"E:\\fgtest\\Spire.Doc.jar-5.data",
"E:\\fgtest\\Spire.Doc.jar-6.data"};
merge(destPath, srcPaths);
}
}
try(ConsumeTime consumeTime = new ConsumeTime()) 这种写法在是JDK1.7 引入了一个新的接口AutoCloseable, 通常它的实现类配合try{}使用,可在 IO 流的使用上,经常可以看到下面这种写法。我们这使用它打印耗时。
/**
* @description:
*/
public class ConsumeTime implements AutoCloseable{
private long start;
public ConsumeTime(){
this.start = System.currentTimeMillis();
}
@Override
public void close() throws Exception {
System.out.println("耗时: " + (System.currentTimeMillis() - start));
}
}