生活中我们经常遇到这样一类问题,就是对于文件上传有大小的限制,尤其是对某个论坛上传附件时,由于论坛的服务器容量比较小,所以在用户上传文件时,进行限制。
比如论坛限制上传大小为2M,我需要上传5M的文件,那么就可以进行将5M文件切割为3个2M大小的碎片文件,上传以后进行合并。接下来就演示文件的切割与合并。
一、切割文件:
1、首先实现需要明确需要切割文件的位置。
2、切割的大小容量
3、切割后碎片文件的存放位置。
4、碎片文件的格式一般是.part。
二、示例代码
public static void splitFile(File file) throws IOException {
//用读取流关联一个源文件
FileInputStream fis =new FileInputStream(file);
//定义一个1M缓冲区,用于存放碎片文件
byte[] bty =new byte[SIZE];
//定义输出流
FileOutputStream fos =null;
//创建目的地
File dir =new File("C:\\Users\\Administrator\\Pictures\\partFiles");
if (!dir.exists()){
dir.mkdirs();
}
//定义一个缓冲区长度变量
int len=0;
int count=0;
while ((len=fis.read(bty))!=-1){
//碎片文件存放位置与格式
fos =new FileOutputStream(new File(dir,(count++)+".part"));
fos.write(bty,0,len);
}
fos.close();
fis.close();
}
调用:
public static void main(String[] args) throws IOException {
File file =new File("C:\\Users\\Administrator\\Pictures\\Screenshots\\0.bmp");
splitFile(file);
}
源文件:
切割后的碎片文件:
三、合并文件
将碎片化的文件合并成切割前的源文件
代码:
private static void mergeFile(File dir) throws IOException {
//存放多个读取源
ArrayList<FileInputStream> al =new ArrayList<FileInputStream>();
for (int i=0; i<=4;i++){
//为list添加多个读取流对象
al.add(new FileInputStream(new File(dir,i+".part")));
}
//将ArrayList转换为枚举
Enumeration<FileInputStream> enumeration = Collections.enumeration(al);
//序列流
SequenceInputStream sis =new SequenceInputStream(enumeration);
//定义合并后的输出位置位于碎片文件文件夹
FileOutputStream fos =new FileOutputStream(new File(dir,"0.bmp"));
//缓冲区
byte[] buf =new byte[1024];
int len=0;
while ((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
调用:
public static void main(String[] args) throws IOException {
File file =new File("C:\\Users\\Administrator\\Pictures\\partFiles");
mergeFile(file);
}
但是以上代码中却有两个问题:
不知道有多少碎片?
不知道源文件的名字?
上面代码都是写死的。
解决方法就是在切割源文件为碎片文件时,获取原文件名和碎片文件个数,存入到一个properties文件中。
四、完善版切割文件
带有文件名和碎片文件次数的配置文件:
话不多说 ,看代码
private static void splitFile_2(File file) throws IOException {
/*
* 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数。 以方便于合并。
* 这个信息为了进行描述,使用键值对的方式。用到了properties对象
*
*/
//用读取流关联一个源文件
FileInputStream fis =new FileInputStream(file);
//定义一个1M缓冲区,用于存放碎片文件
byte[] bty =new byte[SIZE];
//定义输出流
FileOutputStream fos =null;
//创建目的地
File dir =new File("C:\\Users\\Administrator\\Pictures\\partFiles");
if (!dir.exists()){
dir.mkdirs();
}
//定义一个缓冲区长度变量
int len=0;
//记录切割文件的个数
int count=1;
/**
* Properties用于记录文件信息
*/
Properties prop =new Properties();
while ((len=fis.read(bty))!=-1){
//碎片文件存放位置与格式
fos =new FileOutputStream(new File(dir,(count++)+".part"));
fos.write(bty,0,len);
fos.close();
}
prop.setProperty("partcount",count+"");
prop.setProperty("filename",file.getName());
//新建一个文件输出流 创建一个properties配置文件
fos = new FileOutputStream(new File(dir,count+".properties"));
//将properties文件写入到文件中
prop.store(fos,"save file info");
fos.close();
fis.close();
}
、调用:
public static void main(String[] args) throws IOException {
File file =new File("C:\\Users\\Administrator\\Pictures\\Screenshots\\0.bmp");
// splitFile(file);
//自动获取文件名与碎片文件个数,生成配置文件。
splitFile_2(file);
}
切割后得到的文件:
五、完善合并文件:
private static void mergeFile_2(File file) throws IOException {
/**
*1、 获取指定目录下的配置文件对象
* 使用过滤器
*/
File[] dir =file.listFiles(new SuffixFilter(".properties"));
if (dir.length !=1) {
throw new RuntimeException(file+"该目录下没有properties扩展名的文件或者不唯一");
}
//获取配置文件对象
File configFile = dir[0];
/**
* 2、获取该文件中的信息
*/
Properties prop =new Properties();
FileInputStream fis =new FileInputStream(configFile);
//从输入流中读取键值属性信息
prop.load(fis);
//获取碎片个数和源文件的文件名
int count = Integer.parseInt(prop.getProperty("partcount"));
String filename = prop.getProperty("filename");
/**
* 3、 获取该目录下的所有碎片文件
*/
File[] partFiles = file.listFiles(new SuffixFilter(".part"));
if (partFiles.length!=(count-1)){
throw new RuntimeException("碎片文件个数与源文件碎片文件个数不符,文件未上传完整");
}
/**
* 4、将碎片文件和流对象关联 并存储到集合中。
*/
ArrayList<FileInputStream> al =new ArrayList<FileInputStream>();
for (int i=0;i<partFiles.length;i++){
al.add(new FileInputStream(partFiles[i]));
}
/**
* 5、将多个流合并成一个序列流 合并碎片文件
*/
Enumeration<FileInputStream> enumeration = Collections.enumeration(al);
SequenceInputStream sis =new SequenceInputStream(enumeration);
//定义合并后的输出位置位于碎片文件文件夹
FileOutputStream fos =new FileOutputStream(new File(file,filename));
//缓冲区
byte[] buf =new byte[1024];
int len=0;
while ((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
调用:
public static void main(String[] args) throws IOException {
File file =new File("C:\\Users\\Administrator\\Pictures\\partFiles");
//mergeFile(file);
mergeFile_2(file);
}
合并后的文件:
当然其他视频等文件也是如此,就不一一演示了,只需要更改一下切割的源文件目录即可验证。