import java.io.File;
import java.io.IOException;
import org.junit.Test;
public class MainClass {
/**
* 需求:1>.将一个大文件按大小切割成多个小文件,分割后,删除原文件 2>.将多个被切割后的碎片文件合并成一个文件,合并后删除原来的碎片文件
* 思路分析:
* 一、切割文件
* 1.>根据文件路径和文件名获取到该文件
* 2.>切割文件就是将一个文件通过输出流写入到多个文件中,所以要用到一个文件输入流:FileInputStream进行读入内存的操作和
* 多个文件输出流:FileOutputStream类进行写的操作
* 3.>定义缓冲区,进行读取,每读满一个碎片文件进行一次文件流的关闭,关闭后继续写下一个文件
* 4.>碎片文件的名称按照数字命名,第一个文件命名为1.part,第二个命名为2.part
* 5.>将文件名称和文件的个数写入到一个properties文件中去方便下次合并操作
*
* 二、合并文件
* 1.>根据指定的碎片文件的目录,读取properties配置文件
* 2.>根据properties配置文件,获取碎片文件的数量
* 3.>获取所有碎片文件,并添加到List集合中
* 4.>将List集合利用集合工具类Collections中的方法enumeration将集合中的多个流转化为序列流
* 5.>将序列流中的数据写入到指定的文件中去,写完后删掉所有碎片文件
*
* 三、说明
* 本程序支持大文件切割
* 如果正使用的话,还需要测试多线程切割和合并
* 第二个是异常的处理,这个要根据具体需要来处理了
*/
//测试:将E:\split下的1.JPG进行切割
@Test
public void fileSplit(){
//需要切割的文件
File file = new File("E:\\CrossFire_OBV212_Full.exe");
//切割后的路径
File splitedDir = new File("E:\\split");
SplitFile.fileSplit(file,splitedDir);
}
//测试:将E:\split下多个碎片文件进行合并,合并后文件存储到指定目录下
@Test
public void fileMerge() {
//要合并的的碎片文件的目录
File file = new File("E:\\split");
//合并后文件存放的目录
File fileMerged = new File("E:\\merge");
try {
MergeFile.fileMerge(file, fileMerged);
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class SplitFile {
//缓冲区:1M
private static final int BUFFERED_SIZE = 1048576;
//设定每个文件碎片的大小,根据大小来分割文件,每个文件100M
private static final int FILE_SIZE = 104857600;
/**
* 文件切割
* @param file 要切割的文件
* @param splitDir 切割后的文件路径
* */
public static void fileSplit(File file,File splitedDir) {
try {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = null;
byte[] buf = new byte[BUFFERED_SIZE];
int len = 0;
int count = 0;
int filesize = 0;
while((len=fis.read(buf))!=-1){
if(filesize>=FILE_SIZE){
//关闭上一个文件的输出流
fos.close();
//置空上一个文件碎片,准备重新创建新的碎片文件
fos = null;
//重新计算已经写入新的碎片文件的数据大小
filesize = 0;
}
if(fos==null)
fos = new FileOutputStream(new File(splitedDir,(++count)+".part"));
filesize += len;
fos.write(buf, 0, len);
fos.flush();
}
//关闭最后一个写入的碎片文件的流
if(fos != null){
fos.close();
}
fis.close();
writeConfig(splitedDir,file,count);
clearSourceFile(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(IOException ie){
ie.printStackTrace();
}
}
//删除被切割的文件
private static void clearSourceFile(File file) {
file.delete();
}
/**
* @param splitedDir 文件被切割后的存放路径
* @param file 被切割的文件
* @param count 文件个数
* @throws IOException
* */
public static void writeConfig(File splitedDir, File file, int count) throws IOException {
//1.创建properties配置文件
File propfile = new File(splitedDir,(count+1)+".properties");
FileOutputStream fos = new FileOutputStream(propfile);
//2.用Properties类创建对象,将信息写入到内存中
Properties prop = new Properties();
prop.setProperty("filename", file.getName());
prop.setProperty("count", count+"");
//3.将Properties对象store进配置文件
prop.store(fos, "Created By Le.Zhou");
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
public class MergeFile {
//定义配置文件后缀名
private static final String PROPERTIES_SUFFIX = ".properties";
//定义碎片文件后缀名
private static final String PART_SUFFIX = ".part";
//取缓冲区:1M
private static final int BUFFERED_SIZE = 1048576;
/**
* 根据文件路径读取properties配置文件,并合并指定路径下的文件
* @param filepath 要合并的的碎片文件的目录
* @param fileMerged 碎片文件合并后文件的存放目录
* @throws IOException
* */
public static void fileMerge(File filepath, File fileMerged) throws IOException {
//检测碎片文件目录是否正确
if(filepath==null || !filepath.isDirectory()){
throw new RuntimeException("提供的碎片文件目录不是一个目录!");
}
//检测碎片文件合并后的存放目录是否正确
if(!fileMerged.isDirectory()){
boolean flag = fileMerged.mkdirs();
if(!flag)
throw new RuntimeException("创建文件存放路径失败,请提供正确的文件存放路径!");
}
//获取properties配置文件
File[] propFiles = getFilesBySuffix(filepath, PROPERTIES_SUFFIX);
if(propFiles.length != 1){
throw new RuntimeException(filepath.getPath()+"下,后缀为.properties的文件不存在或数量不唯一");
}
Properties prop = getPropObject(propFiles[0]);
//从配置文件中读取碎片文件数量
String count = prop.getProperty("count");
String fileName = prop.getProperty("filename");
if(count==null){
throw new RuntimeException("配置文件中的信息有误:count属性对应的值为空");
}
//获取被分割的文件碎片
File[] partFiles = getFilesBySuffix(filepath,PART_SUFFIX);
List<FileInputStream> flist = new ArrayList<FileInputStream>();
if(Integer.parseInt(count) != partFiles.length)
throw new RuntimeException("配置文件中的count属性的值与实际part文件数量不相符");
//将文件碎片添加到一个集合中
for(File f : partFiles){
flist.add(new FileInputStream(f));
}
//将文件集合转化为序列流
SequenceInputStream sis = fileList2SeqInputStream(flist);
//合并文件
write2Disk(sis, fileMerged, fileName);
//关闭序列流
sis.close();
//清除碎片文件
clearDebrisFiles(filepath);
}
//清除碎片文件
private static void clearDebrisFiles(File filepath) {
File[] file = filepath.listFiles();
for(File f : file){
boolean flag = f.delete();
if(!flag)
throw new RuntimeException(filepath.getPath()+"下,"+f.getName()+"删除失败!");
}
}
//将文件集合转化为序列流
private static SequenceInputStream fileList2SeqInputStream(
List<FileInputStream> flist) {
Enumeration<FileInputStream> enumList = Collections.enumeration(flist);
SequenceInputStream sis = new SequenceInputStream(enumList);
return sis;
}
//根据文件后缀获取文件
private static File[] getFilesBySuffix(File filepath, String suffix) {
File[] propFiles = filepath.listFiles(new FilterBySuffix(suffix));
return propFiles;
}
//获取碎片文件数量
private static Properties getPropObject(File propFiles) throws IOException,
FileNotFoundException {
FileInputStream fis = new FileInputStream(propFiles);
//获取properties配置文件中的信息
Properties prop = new Properties();
prop.load(fis);
fis.close();
return prop;
}
//合并文件
private static void write2Disk(SequenceInputStream sis, File fileMerged, String filename) throws IOException {
FileOutputStream out = new FileOutputStream(new File(fileMerged, filename));
byte[] buf = new byte[BUFFERED_SIZE];
int len = 0;
while((len=sis.read(buf))!=-1){
out.write(buf, 0, len);
}
out.close();
}
}
import java.io.File;
import java.io.FilenameFilter;
/**
* 文件后缀名过滤器
* */
public class FilterBySuffix implements FilenameFilter {
//后缀名
private String suffix;
public FilterBySuffix(String suffix){
this.suffix = suffix;
}
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
文件切割合并程序学习笔记
最新推荐文章于 2024-01-23 01:33:58 发布