今天学习的内容是SequenceInputStream类和文件切割与合并
一、SequenceInputStream类
SequenceInputStream类是一个序列流,用于表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。程序示例(为了方便本例只是将异常抛出):
public class Test89 {
public static void main(String[] args) throws IOException {
//Vector<FileInputStream> v = new Vector<>();
//v.add(new FileInputStream("1.txt"));
//v.add(new FileInputStream("2.txt"));
//v.add(new FileInputStream("3.txt"));
//Enumeration<FileInputStream> en = v.elements();
ArrayList<FileInputStream> list = new ArrayList<>();
for (int i = 1; i < 4; i++) {
list.add(new FileInputStream(i+".txt"));
}
Enumeration<FileInputStream> en = Collections.enumeration(list);
//final Iterator<FileInputStream> it = list.iterator();
//Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
//
//@Override
//public boolean hasMoreElements() {
//
//return it.hasNext();
//}
//
//@Override
//public FileInputStream nextElement() {
//
//return it.next();
//}
//};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("4.txt");
int len = 0;
byte[] buf = new byte[1024];
while((len = sis.read(buf))!=-1){
fos.write(buf, 0, len);
}
sis.close();
fos.close();
}
}
二、文件切割与合并
SequenceInputStream类实际上是用于文件合并的。文件切割就是使用不同输出流将数据写入不同文件,这些文件叫做碎片文件。下面是文件切割与合并的程序示例(面试要点):
public class Test90 {
private static final int SIZE = 1024 * 1024;
public static void main(String[] args) {
File file = new File("萧敬腾 - Beautiful Love.mp3");// 要切割的文件
File dir = new File("partfiles");// 碎片文件及配置文件放置的目录
splitFile(file, dir);// 将指定文件切割,碎片文件放置到指定目录
mergeFile(dir);// 将指定目录中的碎片文件合并
}
// 文件合并
private static void mergeFile(File dir) {
// 获取指定目录下的配置文件
File[] files = dir.listFiles(new FilterByProperties());
if (files.length != 1) {
throw new RuntimeException(dir + ",该目录下没有配置文件,或者配置文件不唯一!!");
}
File confile = files[0];
// 将配置文件的内容读取到属性集中,并获取信息
Properties prop = new Properties();
FileInputStream fis = null;
try {
fis = new FileInputStream(confile);
prop.load(fis);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException("关闭资源失败!");
}
}
}
int partcount = Integer.parseInt(prop.getProperty("partcount"));// 获取碎片文件个数
String filename = prop.getProperty("name");// 获取被切割文件的名称
// 将碎片文件与输入流关联并存在集合中
ArrayList<FileInputStream> list = new ArrayList<>();
for (int i = 1; i < partcount; i++) {
FileInputStream fis_ = null;
try {
fis_ = new FileInputStream(new File(dir, i + ".part"));
} catch (IOException e) {
e.printStackTrace();
}
list.add(fis_);
}
// 将多个流合并为一个序列流
Enumeration<FileInputStream> en = Collections.enumeration(list);
SequenceInputStream sis = null;
sis = new SequenceInputStream(en);
// 合并碎片文件
FileOutputStream fos = null;
try {
fos = new FileOutputStream("new_" + filename);
int len = 0;
byte[] buf = new byte[1024];
while ((len = sis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException("关闭资源失败!");
}
}
if (sis != null) {
try {
sis.close();
} catch (IOException e) {
throw new RuntimeException("关闭资源失败!");
}
}
}
}
// 切割文件
private static void splitFile(File file, File dir) {
Properties prop = new Properties();// 使用配置文件记录被切割文件的名称以及碎片文件的个数,便于文件合并
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(file);
byte[] buf = new byte[SIZE];// 定义一个1M的缓冲区
int len = 0;
int count = 1;
if (!dir.exists()) {
dir.mkdir();
}
while ((len = fis.read(buf)) != -1) {
fos = new FileOutputStream(new File(dir, (count++) + ".part"));// 将碎片文件放在指定目录中
// 这里就是文件切割的关键!
fos.write(buf, 0, len);
fos.close();
}
prop.setProperty("partcount", String.valueOf(count));// 记录碎片文件的个数
prop.setProperty("name", file.getName());// 记录被切割文件的名称
fos = new FileOutputStream(new File(dir, count + ".properties"));// 目的地为配置文件的输出流
prop.store(fos, "file info");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException("关闭资源失败!");
}
}
}
}
}
// 过滤器
class FilterByProperties implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".properties");
}
}