好吧,既然算法这个高深的问题还不能游刃有余,那就先巩固巩固基础吧!
我就根据自己的学习经历,来复习一下以前学过的知识吧!
首先声明,这些概念非本人创造,是本人学习过程中接触到的。然后我根据自己的理解空闲时间独立完成。所有源代码全部是自己原创!这都是站在巨人肩膀上的结果
今天写个文件切割器:
文件切割器就是把把一些大文件切割成相同大小(尾巴除外)的子文件。为什么要这么做呢?这是因为在一些论坛等网站由于服务器性能等原因,上传的文件大小一般是不能超过一定大小的。我们为了上传一些大文件,就不得不把这些大文件切割成一份一份的小文件,用户下载下来之后可以合并还原成原来的文件。
文件切割器涉及的一些核心东西就是Java的IO流,因为文件存储在硬盘上,一般情况下,要切割的文件可能是一些视频流或者音频流文件,所以一般要用到字节流。要将文件从硬盘读到内存,很明显就要用到FileInputStream 这个流对象。因为我们要按指定的大小来切割文件,所以就应该手动定义缓冲区,所以就不对这个流进行包装了。
如何将一个大的文件流放到小的文件流中呢?这里就要用到一个循环了,每一次把缓冲区的数据及时刷到FileOutputStream中去,并对文件命名。
关于文件的命名,为了不覆盖前一次的数据,我们可以使用一个唯一的数据来命名,这就想到了时间戳。可以对系统当前时间的毫秒值进行获取来命名,如果觉得数据大了可以将其取余。还有一种简单的方法,那就是搞一个计数器,用原文件文件名+计数序号作为碎片文件文件名。这种方式也可以。而且更加具有实用性。所以我的用这主。关于文件后缀名,其实Window中文件后缀名只是为了区分不同的应用程序的文件数据。没有其他作用。所以这里的后缀名可以自定义一个独特的。不过,一般我们用.part作为后缀名,通俗易懂。
在切割的过程中要注意一个问题是切割后的合并问题。合并碎片文件就要知道这文件以前的文件名称是什么,后缀名是什么,切割分数有没有等等这些信息。所以应该在切割的过程中应该将这些数据存储到一个文件当中。因为数据较少且简单。所以就用一个properties文件储存就可以了。
大概的思想就是这样了,具体实现过程我们直接看源码:
/**
*Mar 28, 2013
*Copyright(c)JackWang
*All rights reserve
*@Author <a href="mailto:wangchengjack@163.com">JackWang</a>
*/
package com.myjava.function;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Properties;
import com.myjava.myexception.DataErrorException;
import com.myjava.myexception.NoSuchFileException;
/**
* 实现大文件切割
* 思路:文件类型不确定,所以应该用字节流
* 可以自定义缓冲区,缓冲区大小为切割部分大小
* 在将切割后的流存到文件中
* 应该有一个文件用于记录切割信息,如原始文件名,切割份数,在合并文件时读取这些信息来确定文件类型等
* 切割文件的后缀名可以自定义,一般用.part
* @author WangCheng
*
*/
public class SplitFiles {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
File file = new File("I:"+File.separator+"梁祝.mp3"); //定义文件对象
boolean result = splitFiles(file,1);
System.out.println(result);
}
/**
*
* @param file 要切割的文件对象
* @param i 要切割的大小
* @return 切割是否成功
* @throws IOException
*/
public static boolean splitFiles(File file, int i) throws IOException {
//参数合法性检查
if(!file.exists()){
throw new NoSuchFileException("文件不存在,请检查!!");
}
if(i < 0){
throw new DataErrorException("数据不合法!");
}
//切割文件存放处
File dir = new File("I:"+File.separator+"PartFiles"); //自定义碎片文件存放路径
if (!dir.exists()) {
dir.mkdirs();
}
//创建原文件流
FileInputStream fis = new FileInputStream(file);
//创建缓冲区
byte[] buff = new byte[1024*1024*i];
int len = 0;
int count = 0; //记录切割份数
String fileName = getFileName(file.getName());
while((len=fis.read(buff))!=-1){
FileOutputStream fos = new FileOutputStream(new File(dir,fileName+(++count)+".part"));
fos.write(buff, 0, len);
fos.close();
}
//记录文件信息
recordFileInfo(file.getName(),count);
fis.close();
return true;
}
public static void recordFileInfo(String fileName, int count) throws FileNotFoundException, IOException {
Properties prop = new Properties();
File countFile = new File("I:"+File.separator+"PartFiles",getFileName(fileName)+".properties");
prop.setProperty("fileName", fileName);
prop.setProperty("count", count+"");
PrintStream out = new PrintStream(countFile);
prop.store(out, "sava file Infomation");
// prop.list(System.out);
}
public static String getFileName(String fileName) {
return fileName.substring(0,fileName.indexOf("."));
}
}
关于代码中抛出的自定义异常,我定义了一个异常包,继承了RuntimeException类,没啥技术含量,就不贴了!
好了,到此为止就完成了文件切割器的核心代码。欢迎大家批评和指导!
明天上文件合并器!