好吧,既然算法这个高深的问题还不能游刃有余,那就先巩固巩固基础吧!

我就根据自己的学习经历,来复习一下以前学过的知识吧!

首先声明,这些概念非本人创造,是本人学习过程中接触到的。然后我根据自己的理解空闲时间独立完成。所有源代码全部是自己原创!这都是站在巨人肩膀上的结果

今天写个文件切割器:

文件切割器就是把把一些大文件切割成相同大小(尾巴除外)的子文件。为什么要这么做呢?这是因为在一些论坛等网站由于服务器性能等原因,上传的文件大小一般是不能超过一定大小的。我们为了上传一些大文件,就不得不把这些大文件切割成一份一份的小文件,用户下载下来之后可以合并还原成原来的文件。


文件切割器涉及的一些核心东西就是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类,没啥技术含量,就不贴了!



好了,到此为止就完成了文件切割器的核心代码。欢迎大家批评和指导!

明天上文件合并器!