ITEEDU

Java Gossip: SequenceInputStream

您将一个档案分割为数个档案,接下来要将之再度组合还原为原来的档案,最基本的作法是使用数个 FileInputStream来开启分割后的档案,然后一个一个档案的读取,并连续写入至同一个FileOutputStream中,在这中间,您必须 要自行判断每一个分割档案的读取是否完毕,如果完毕就换读取下一个档案。

如果您使用SequenceInputStream就不用这么麻烦,SequenceInputStream可以看作是数个 InputStream对象的组合,当一个InputStream对象的内容读取完毕后,它就会取出下一个InputStream对象,直到所有的 InputStream对象都读取完毕为止。

下面这个程序是SequenceInputStream的使用示范,它可以将指定的档案进行分割,也可以将分割后的档案还原为一个档案:

SequenceStreamDemo.java
package onlyfun.caterpillar;
import java.util.*;
import java.io.*;
public class SequenceStreamDemo {
	public static void main(String[] args) {
		try {
			// args[0]: 指定分割(s)或连接(c)
			switch (args[0].charAt(1)) {
				case 's':
				// args[1]: 每个分割档案的大小
				int size = Integer.parseInt(args[1]);
				// args[2]: 指定要被分割的文件名称
				seperate(args[2], size);
				break;
				case 'c':
				// args[1]: 指定要被组合的档案个数
				int number = Integer.parseInt(args[1]);
				// args[2]: 组合后的文件名称
				concatenate(args[2], number);
				break;
			}
		}
		catch(ArrayIndexOutOfBoundsException e) {
			System.out.println(
			"Using: java UseSequenceStream [-s/-c]" +
			" (size/number) filename");
			System.out.println("-s: 分割档案\n-c: 组合档案");
		}
		catch(IOException e) {
			e.printStackTrace();
		}
	}
	// 分割档案
	public static void seperate(String filename, int size)
	throws IOException {
		FileInputStream fileInputStream =
		new FileInputStream(new File(filename));
		BufferedInputStream bufInputStream =
		new BufferedInputStream(fileInputStream);
		byte[] data = new byte[1];
		int count = 0;?
		// 从原档案大小及指定分割的大小
		// 决定要分割为几个档案
		if(fileInputStream.available() % size == 0)
		count = fileInputStream.available() / size;
		else
		count = fileInputStream.available() / size + 1;
		// 开始进行分割
		for(int i = 0; i < count; i++) {
			int num = 0;
			// 分割的档案加上底线与编号
			File file = new File(filename + "_" + (i + 1));
			BufferedOutputStream bufOutputStream =
			new BufferedOutputStream(
			new FileOutputStream(file));
			while(bufInputStream.read(data) != -1) {
				bufOutputStream.write(data);
				num++;
				if(num == size) { // 分割出一个档案
					bufOutputStream.flush();
					bufOutputStream.close();
					break;
				}
			}
			if(num < size) {
				bufOutputStream.flush();
				bufOutputStream.close();
			}
		}
		System.out.println("分割为" + count + "个档案");
	}
	// 连接档案
	public static void concatenate(String filename,
	int number) throws IOException {
		// 收集档案用的List
		List list =
		new ArrayList();
		for(int i = 0; i < number; i++) {
			// 文件名必须为底线加上编号
			File file = new File(filename + "_" + (i+1));
			list.add(i, new FileInputStream(file));
		}
		final Iterator iterator = list.iterator();
		// SequenceInputStream 需要一个Enumeration对象来建构
		Enumeration enumation =
		new Enumeration() {
			public boolean hasMoreElements() {
				return iterator.hasNext();
			}
			public InputStream nextElement() {
				return iterator.next();
			}
		};
		// 建立SequenceInputStream
		// 并使用BufferedInputStream
		BufferedInputStream bufInputStream =
			new BufferedInputStream(
				new SequenceInputStream(enumation),
					8192);
		BufferedOutputStream bufOutputStream =
			new BufferedOutputStream(
				new FileOutputStream(filename), 8192);
					byte[] data = new byte[1];
		// 读取所有档案数据并写入目的地档案
		while(bufInputStream.read(data) != -1)
		bufOutputStream.write(data);
		bufInputStream.close();
		bufOutputStream.flush();
		bufOutputStream.close();
		System.out.println("组合" + number + "个档案 OK!!");
	}
}

分割档案时的范例如下:

java onlyfun.caterpillar.SequenceStreamDemo -s 1048576 test.zip
分割为6个档案

组合档案时的范例如下:

java onlyfun.caterpillar.SequenceStreamDemo -c 6 test.zip
组合6个档案 OK!!