Java 分割与合并文件

概要:

分割文件时,如果是程序自动拆分为多个文件,那么后缀分别为“.part序号”,这样就可以方便文件合并了。

分割文件,指定小文件的长度,即字节数,根据File的length()方法获得大文件的长度,以确定目标小文件的数目。用文件输入流顺序地读取大文件的数据,将数据分流到每个小文件的输出流里。

如果指定的小文件比原文件都还要大,为了不动原文件,就生成另一个文件,后缀为".block",这样可以保证原文件。

合并时,读取每个小文件的输入流,将所有内容依次按顺序写入到目标大文件的输出流里。

| |目录

代码

package net.xsoftlab.baike;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.util.Scanner;

public class SeparatorFile {

	String FileName = null;// 原文件名
	long FileSize = 0;// 原文件的大小
	long BlockNum = 0;// 可分的块数

	public SeparatorFile() {
	}

	// 取得原文件的属性
	private void getFileAttribute(String fileAndPath) {
		File file = new File(fileAndPath);// 创建文件,fileAndPath包括路径、原文件名
		FileName = file.getName();// 获得文件的名字
		FileSize = file.length();// 获得文件大小
	}

	// 取得分块数
	private long getBlockNum(long blockSize) {
		long fileSize = FileSize;// 赋值
		if (fileSize <= blockSize)// 如果分块小只够分一个块
			return 1;// 返回
		else {
			if (fileSize % blockSize > 0) {// 判断原文件大小与每一块是否整除
				return (fileSize / blockSize) + 1;
			} else
				return fileSize / blockSize;
		}
	}

	// 获得拆分后每块的文件名包括路径
	private String generateSeparatorFileName(String fileAndPath, int currentBlock) {
		String separatorFile = fileAndPath + ".part" + currentBlock;
		System.out.println("文件拆分成:" + separatorFile);
		return separatorFile;// 返回拆分的块的文件名
	}

	// 往硬盘写文件
	private boolean writeFile(String fileAndPath, String fileSeparateName, long blockSize, long beginPos) {
		RandomAccessFile raf = null;
		FileOutputStream fos = null;
		byte[] bt = new byte[1024];// 创建数组存取数据
		long writeByte = 0;
		int len = 0;
		try {
			raf = new RandomAccessFile(fileAndPath, "r");// 创建随机访问文件对象,以只读的方式
			raf.seek(beginPos);// 设置对象开始读取的位置
			fos = new FileOutputStream(fileSeparateName);// 根据传入文件名创建文件输出流
			while ((len = raf.read(bt)) > 0) {// 循环读取数据
				if (writeByte < blockSize)// 如果当前块还没有写满
				{
					writeByte = writeByte + len;
					if (writeByte <= blockSize)
						fos.write(bt, 0, len);// 如果当前块没有写满
					else {// 当前块写满
						len = len - (int) (writeByte - blockSize);
						fos.write(bt, 0, len);
					}
				}
			}
			fos.close();// 关闭文件输出流
			raf.close();// 关闭随机访问对象
		} catch (Exception e) {// 捕获异常
			e.printStackTrace();
			try {
				if (fos != null)// 确保文件输出流关闭
					fos.close();
				if (raf != null)// 确保随机访问对象关闭
					raf.close();
			} catch (Exception f) {// 捕获异常
				f.printStackTrace();
			}
			return false;
		}
		return true;
	}

	// 折分文件
	private boolean separatorFile(String fileAndPath, long blockSize) {
		getFileAttribute(fileAndPath);// 将文件的名及大小属性取出来
		BlockNum = getBlockNum(blockSize);// 取得分块总数
		System.out.println("共拆分成" + BlockNum + "个文件");
		if (BlockNum == 1)// 如果只能够分一块,就一次性写入
			blockSize = FileSize;
		long writeSize = 0;// 每次写入的字节
		long writeTotal = 0;// 已经写了的字节
		String currentNameAndPath = null;
		for (int i = 1; i <= BlockNum; i++) {
			if (i < BlockNum)
				writeSize = blockSize;// 取得每一次要写入的文件大小
			else
				writeSize = FileSize - writeTotal;
			if (BlockNum == 1)
				currentNameAndPath = fileAndPath + ".block";// 每个块的后缀加为block
			else
				currentNameAndPath = generateSeparatorFileName(fileAndPath, i);
			if (!writeFile(fileAndPath, currentNameAndPath, writeSize, writeTotal))// 循环往硬盘写文件
				return false;
			writeTotal = writeTotal + writeSize;
		}
		return true;
	}

	private String[] separatorFiles(String fileAndPath, long blockSize) {// 获得折分文件名
		BlockNum = getBlockNum(blockSize);// 取得分块总数
		if (BlockNum == 1)// 如果只能够分一块,就一次性写入
			blockSize = FileSize;
		String[] nameAndPath = new String[(int) BlockNum];
		String currentName = null;
		for (int i = 1; i <= BlockNum; i++) {
			if (BlockNum == 1)
				currentName = fileAndPath + ".block";// 每个块的后缀加为block
			else
				currentName = generateSeparatorFileName(fileAndPath, i);
			nameAndPath[i - 1] = currentName;// 将文件绝路径放入数组中
		}
		return nameAndPath;
	}

	public static String unite(String[] fileNames, String TargetFileName) throws Exception {// 合并文件
		File inFile = null;
		File outFile = new File(TargetFileName);// 构建文件输出流
		FileOutputStream out = new FileOutputStream(outFile);// 创建文件输出流
		for (int i = 0; i < fileNames.length; i++) {// 循环显示文件
			inFile = new File(fileNames[i]);// 打开文件输入流
			FileInputStream in = new FileInputStream(inFile);
			int c;
			while ((c = in.read()) != -1) {// 从输入流中读取数据,并写入到文件数出流中
				out.write(c);
			}
			in.close();
		}
		out.close();
		return outFile.getAbsolutePath();// 返回合并后文件绝对路径
	}

	public static void main(String[] args) throws Exception {
		SeparatorFile separator = new SeparatorFile();
		System.out.println("1.输入要拆分的文件(包括路径和后缀)");
		Scanner scan = new Scanner(System.in);// 键盘输入
		String fileAndPath = scan.next();// 获得键盘输入值
		long blockSize = 100;// 每一个文件块的大小,大小是按字节计算
		if (separator.separatorFile(fileAndPath, blockSize)) {// 调用方法进行拆分
			System.out.println("文件折分成功!");
		} else {
			System.out.println("文件折分失败!");
		}
		System.out.println("2.输入合并后的目标文件(包括路径和后缀)");
		String targetName = scan.next();// 获得键盘输入值
		String result = unite(separator.separatorFiles(fileAndPath, blockSize), targetName);
		System.out.println("合并结果:" + result);
	}
}


评论关闭
评论 还能输入200
评论关闭
评论 还能输入200
  • 全部评论(0)
资料加载中...
已关注 , 取消