1 文件切割
切割方式:
1 按大小切,文件有多大,每份切多少,都是事先规定好的
2 按重量切,不管文件有多大,就切 N份 — 这种方式比较好有几个文件,就需要几个输出流。一个文件,关联一个流
用读取流 关联源文件
代码实现
FileInputStream fis = new FileInputStream(file);
/*
定义一个1M的缓冲区
如果定义的是 100M 缓冲区,那就 循环往里写,循环写100次
*/
byte[] buf = new byte[SIZE];
FileOutputStream fos = null; // 创建目的
int len = 0;
int count = 1;
File dir = new File("c:\\partfiles"); // 定义切割的文件存放的位置
if(!dir.exists())
dir.mkdirs();
while( (len=fis.read(buf)) != -1 ) {
// --- 注释
fos = new FileOutputStream(new File(dir,(count++)+".part") );
fos.write(buf,0,len);
}
fos.close();
fis.close();
注:
// — 注释 下面 写
fos = new FileOutputStream("1.txt");
不行
因为我们产生的是 碎片文件,有好多个,不能只写一个文件
文件要有编号,所以,对文件名,要进行处理
扩展名是 txt 也不靠谱,因为切的文件可能是 mp3 mp4 jpg等
专业的碎片 起名 part 1.part
2 文件合并
//将 碎片文件和流对象 关联 并存储到集合中
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=0; x<partFiles.length; x++){
al.add(new FileInputStream( new File(dir,x+".part")));
}
//将多个流合并成一个序列流
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream(new File(dir,filename));
byte[] buf = new byte[1024];
int len =0;
while( (len=sis.read(buf)) !=-1 ) {
fos.write(buf,0,len);
}
fos.close();
sis.close();
3 改进
上面的写法,有两处不足:
1 切割时,不知道被切割文件的个数
2 合并前,不知道原来文件的类型 — 2 的写法是按照 默认知道来做的思路:碎片记录的是,主体文件的内容,再弄一文件,记录碎片的信息
文件切割:
带着配置信息的切割
1 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数。 以方便于合并
这个信息为了进行描述,使用键值对的方式。用到了properties对象
Properties prop = new Properties();
2 将被切割文件的信息保存到prop集合中
prop.setProperty("partcount", count+"");
// 碎片文件的个数
prop.setProperty("filename", file.getName());
3 如果有N个碎片,properties命名为 N+1.properties
fos = new FileOutputStream(new File(dir,count+".properties"));
4 将prop集合中的数据存储到文件中
prop.store(fos, "save file info");
知识储备
基础知识非常重要,再复杂的功能也是由一个个基础的方法组成的,熟练,深刻的理解,掌握基础知识!!!1 关于File 的构造函数的理解
File(File parent,String Child)
File(String parent,String child)
根据给定 parent路径名 和 child路径名 创建一个新的 File实例
2 关于 count++ 的理解
命名切割的文件是 1 2 3 4 ,为什么 count =5
很简单 i++; 先使用,再加1
int x=1;
int y= x++;;
for(int i=0;i<4;i++){
System.out.println(“y=”+y);
System.out.println(“x=”+x);
}输出结果 y= 1,2,3,4 x= 2,3,4,5
因为 y=x++; 是先使用再加 1 ,x 直接输出 x++, 加1后的结果
代码
public class SplitFileDemo {
// 定义一个 3M大小的 缓冲区 写 3145728比较好,写 1024*1024*3,
// 程序在运行的时候,还要先运算一遍,影响效率
private static final int SIZE = 3145728;
public static void main(String[] args) throws IOException {
File file = new File("E:\\tm.mp3");
splitFile(file);
}
private static void splitFile(File file) throws IOException {
// 用读取流 关联源文件
FileInputStream fis = new FileInputStream(file);
// 定义一个 3M的缓冲区
byte[] buf = new byte[SIZE];
// 创建目的
FileOutputStream fos = null;
int len = 0;
int count = 1;
/*
* 切割文件时,必须记住被切割的文件的名称,以及切割出来的碎片文件的个数
* 以方便合并。
* 这个信息为了进行描述,使用键值对的方式,用到了 properties对象
*/
Properties prop = new Properties();
File dir = new File("E:\\partFiles"); // 定义切割文件存放的位置
if(!dir.exists()){
dir.mkdirs();
}
while((len=fis.read(buf))!=-1){
fos = new FileOutputStream(new File(dir,(count++)+".part"));
fos.write(buf,0,len);
fos.close();
}
// 将被切割文件的信息 保存到 prop集合中
/*
* setProperty(String value,String key)
* 调用 Hashtable的方法 put
*/
prop.setProperty("partcount",count+"");
prop.setProperty("filename",file.getName());
// 如果有N个碎片,properties命名为 N+1.properties
fos = new FileOutputStream(new File(dir,count+".properties"));
// 将 prop集合中的数据 存储到文件中
prop.store(fos,"save file info");
fos.close();
fis.close();
}
}
文件合并
1 先拿到该目录下的 配置文件对象
配置信息拿不到,或者文件不存在,就不用合并了
配置文件怎么拿我们不知道配置文件的信息,但是知道配置文件的扩展名是 .properties
所以要准备一个过滤器
File[] files = dir.listFiles(new SuffixFilter(".properties"));
// 获取指定目录下的配置文件对象2 记录配置文件对象
File confile = files[0];
3 获取该文件中的信息
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(confile);
prop.load(fis);
String filename = prop.getProperty(“filename”);
int count = Integer.parseInt(prop.getProperty(“partcount”));4 获取该目录下的所有碎片文件
File[] partFiles = dir.listFiles(new SuffixFilter(".part"));
5 将碎片文件和流对象关联 并存储到集合中
ArrayList al = new ArrayList();
for(int x=0; x<partFiles.length; x++){
al.add(new FileInputStream(partFiles[x]));
}6 将多个流合并成一个序列流
过滤器
public class SuffixFilter implements FilenameFilter{
private String suffix;
public SuffixFilter(String suffix){
super();
this.suffix = suffix;
}
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
合并代码
public class MergeFileDemo {
/**
* 文件合并
* @throws IOException
*/
public static void main(String[] args) throws IOException {
File dir = new File("E:\\partFiles"); // 先关联 要合并的文件
mergeFile(dir);
}
private static void mergeFile(File dir) throws IOException {
// 合并文件,给的是文件夹,里面有一堆文件/目录
// 获取指定目录下的 配置文件对象
File[] files = dir.listFiles(new SuffixFilter(".properties"));
if(files.length !=1){
throw new RuntimeException(dir+",该目录下没有properties扩展名的文件或者不唯一");
}
// 记录配置文件对象
File confile = files[0];
// 获取该文件中的信息
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(confile);
prop.load(fis);
String filename = prop.getProperty("filename");
int count = Integer.parseInt(prop.getProperty("partcount"));
// 获取该目录下的所有碎片文件
File[] partFiles = dir.listFiles(new SuffixFilter(".part"));
if(partFiles.length !=(count-1)){
throw new RuntimeException(" 碎片文件不符合要求,个数不对!应该"+count+"个");
}
// 将碎片文件 和 流对象 关联,并存储到集合中
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=0;x<partFiles.length;x++){
al.add(new FileInputStream(partFiles[x]));
}
// 将多个流 合并成一个流
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream(new File(dir,filename));
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}