当需要直接把信息输出到文件中的时候,并且想要每次输入完成后立即把信息输出到文件中,演示如下
1 private static void function_demo2() throwsIOException {2 BufferedReader reader = new BufferedReader(newInputStreamReader(System.in));3 PrintWriter writer = new PrintWriter(new FileWriter("writer.txt"), true);4 String line = null;5 while ((line = reader.readLine()) != null) {6 if (line.equals("over")) {7 break;8 } else{9 writer.println(line.toUpperCase());10 }11 }12 writer.close();13 reader.close();14 }
三,序列流SequenceInputStream
表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
此流相当于是一个集合,把若干个流放入到此集合,然后一个流接着一个流的读取,当完第一个判断此集合里是否还有其它流,若有接着读取,读到最后一个返回-1。
此流有两个构造函数,一个是接收两个InputStream类型的参数,即接收两个流,若想读取多个流,则用接收Enumeration类型的参数。
接下来我们用一个需求把此流演示一下,需求是把三个txt文档合并为一个文档
1 private static void function_demo3() throwsIOException {2 Vector v = new Vector();//定义Vector集合用于存储所有的流
3 v.add(new FileInputStream("1.txt"));4 v.add(new FileInputStream("2.txt"));5 v.add(new FileInputStream("3.txt"));6 Enumeration enu = v.elements();//因为SequenceInputStream接收的是Enumeration类型的参数,所以用Vector集合
7 SequenceInputStream sis = newSequenceInputStream(enu);8 OutputStream out = new FileOutputStream("4.txt");9 byte[] bt = new byte[1024];10 int len = 0;11 while ((len = sis.read(bt)) != -1) {12 out.write(bt, 0, len);13 }14 out.close();15 sis.close();//序列流的关闭会把其中的所有的流都关闭
16 }
大家都知道,Vector对象效率太低,开发中一般会用ArrayList,那么接下来就把Vector换成ArrayList,演示如下
1 private static void function_demo3() throwsIOException {2 ArrayList al = new ArrayList();//定义ArrayList集合接所有的流
3 al.add(new FileInputStream("1.txt"));4 al.add(new FileInputStream("2.txt"));5 al.add(new FileInputStream("3.txt"));6 Iterator it = al.iterator();//获取一个Iterator对象7 //没有枚举对象就new一个出来,然后重写里面的两个方法返回iterator对象的hasNext和next方法
8 Enumeration enumeration = new Enumeration() {9 @Override10 public booleanhasMoreElements() {11 returnit.hasNext();12 }13
14 @Override15 publicFileInputStream nextElement() {16 returnit.next();17 }18 };19 SequenceInputStream sis = newSequenceInputStream(enumeration);20 OutputStream out = new FileOutputStream("4.txt");21 byte[] bt = new byte[1024];22 int len = 0;23 while ((len = sis.read(bt)) != -1) {24 out.write(bt, 0, len);25 }26 out.close();27 sis.close();//序列流的关闭会把其中的所有的流都关闭
28 }
看起来很麻烦的样子,有没有办法简化一下呢?Collections集合类里为我们提供了一个获取Enumeration的工具,演示如下:
1 private static void function_demo3() throwsIOException {2 ArrayList al = new ArrayList();//定义ArrayList集合接所有的流
3 al.add(new FileInputStream("1.txt"));4 al.add(new FileInputStream("2.txt"));5 al.add(new FileInputStream("3.txt"));6 Iterator it = al.iterator();//获取一个Iterator对象
7 Enumeration enumeration =java.util.Collections.enumeration(al);8 SequenceInputStream sis = newSequenceInputStream(enumeration);9 OutputStream out = new FileOutputStream("4.txt");10 byte[] bt = new byte[1024];11 int len = 0;12 while ((len = sis.read(bt)) != -1) {13 out.write(bt, 0, len);14 }15 out.close();16 sis.close();//序列流的关闭会把其中的所有的流都关闭
17 }
四,文件切割及合并
把一个大的文件切割成若干个小的文件,方便文件上传的时候对大小的限制,实现代码如下
1 private static final int SIZE = 1024 * 1024;2
3 private static void function_demo4() throwsIOException {4 File dir = new File("c:\\");5 File file = new File(dir, "1.bmp");//需要分隔的源文件
6 FileInputStream inputStream = new FileInputStream(file);//字节流对象
7 byte[] bt = new byte[SIZE];//缓冲数组,大小由常量固定8 //由于需要分隔文件,所以此处不能实例化输出流对象,需要在读取的时候每读取一次实例化一个输出流对象
9 FileOutputStream outputStream = null;10 File dest = null;//由于切割文件,每个被切割出来的文件名称不同,所以此处File不能实例化,需要在每切割出来一个文件则实例化一个File对象
11 intlen;12 int i = 0;//为切割出来的每个文件名添加序列
13 while ((len = inputStream.read(bt)) != -1) {14 i++;15 dest = new File(dir, "\\temp\\" + i + ".part");//切割出来的文件对象
16 outputStream = new FileOutputStream(dest);//实例化每个输出流对象
17 outputStream.write(bt, 0, len);//读取每个切割出来的文件
18 outputStream.close();//关闭每个读取流对象
19 }20 inputStream.close();//关闭输入流对象
21 }
把切割后的文件合并为一个文件,实现代码如下
1 private static void function_demo5() throwsIOException {2 File dir = new File("C:\\temp");//源目录对象
3 ArrayList al = new ArrayList();//存储输入流的集合对象
4 FileInputStream inputStream = null;//根据源文件的个数实例化输入流对象,因需要循环源文件数量,所以此处实例为null
5 File file = null;//源文件名字不一样,所以此处实例化为null
6 for (int i = 1; i < 4; i++) {7 file = new File(dir, i + ".part");//源文件名
8 inputStream = new FileInputStream(file);//封装输入流对象
9 al.add(inputStream);//将输入流对象添加到流集合对象中
10 }11 Enumeration enu = java.util.Collections.enumeration(al);//从输入流集合对象中获取Enumeration对象以便传给序列流SequenceInputStream
12 SequenceInputStream sis = new SequenceInputStream(enu);//封装序列流对象
13 BufferedInputStream bis = new BufferedInputStream(sis);//缓冲输入流对象
14 File dest = new File(dir, "4.bmp");//封装合并全的文件名及路径
15 FileOutputStream outputStream = new FileOutputStream(dest);//输出流对象
16 BufferedOutputStream bos = new BufferedOutputStream(outputStream);//输出缓冲对象17 //以下代码是循环读取及写入流对象,关闭流
18 intlen;19 while ((len = bis.read()) != -1) {20 bos.write(len);21 }22 bos.close();23 bis.close();24 }
五,完整的文件切割与合并
由上面的例子大家可以考虑几个问题
1,被切割后的文件数量在合并的时候并不知道
2,源文件的文件扩展名在合并的时候并不知道
鉴于这两点,在切割文件的时候应当把这两个信息写入到配置文件中,在合并文件的时候先读取配置文件中的信息然后检验配置文件中的信息和切割后的文件信息是否一致,若一致再进行合并操作,具体操作演示如下
1 private static final int SIZE = 1024 * 1024;2
3 private static void function_demo6() throwsIOException {4 File dir = new File("c:\\");5 File file = new File(dir, "1.bmp");//需要分隔的源文件
6 FileInputStream inputStream = new FileInputStream(file);//字节流对象
7 byte[] bt = new byte[SIZE];//缓冲数组,大小由常量固定8 //由于需要分隔文件,所以此处不能实例化输出流对象,需要在读取的时候每读取一次实例化一个输出流对象
9 FileOutputStream outputStream = null;10 File dest = null;//由于切割文件,每个被切割出来的文件名称不同,所以此处File不能实例化,需要在每切割出来一个文件则实例化一个File对象
11 intlen;12 int i = 0;//为切割出来的每个文件名添加序列
13 while ((len = inputStream.read(bt)) != -1) {14 i++;15 dest = new File(dir, "\\temp\\" + i + ".part");//切割出来的文件对象
16 outputStream = new FileOutputStream(dest);//实例化每个输出流对象
17 outputStream.write(bt, 0, len);//读取每个切割出来的文件
18 outputStream.close();//关闭每个读取流对象
19 }20 inputStream.close();//关闭输入流对象
21 String fileName = file.getName();//获取源文件名
22 File fileCountFilter = new File("C:\\temp");//被切割的文件的存放目录
23 String[] fileCountArray = fileCountFilter.list(new PartFileNameFilter(".part"));//过滤被切割的文件
24 int count = fileCountArray.length;//被切割的文件数量
25 Properties prop = new Properties();//把切割的文件信息存储到配置文件中
26 prop.setProperty("fileName", fileName);//源文件名
27 prop.setProperty("count", String.valueOf(count));//被切割出来的文件数量
28 Writer writer = new FileWriter("C:\\temp\\config.properties");29 prop.store(writer, "cut file info");30 }
1 private static void function_demo7() throwsIOException {2 File dir = new File("C:\\temp");//源目录对象
3 String[] partFileArray = dir.list(new PartFileNameFilter(".part"));4 int partFileCount = partFileArray.length;//获取源目录中被切割的文件数量
5 File[] propertiesFile = dir.listFiles(new PartFileNameFilter(".properties"));//过滤配置文件
6 String fileName = null;7 int cutFileCount = 0;8 if (propertiesFile.length != 1) {//若切割文件配置文件不唯一则抛出异常
9 throw new RuntimeException("切割文件的配置信息没有或多于一个,无法完成文件合并");10 } else {//否则读取配置文件信息
11 Properties prop = newProperties();12 prop.load(new FileReader(propertiesFile[0]));13 fileName = prop.getProperty("fileName");//获取配置文件中的源文件名
14 cutFileCount = Integer.parseInt(prop.getProperty("count"));//获取配置文件中被切割后的文件数量
15 if (partFileCount != cutFileCount) {//若读取到的配置文件中的文件数与源目录中被切割的文件数量不一样,则抛出异常
16 throw new RuntimeException("文件不全,无法进行文件合并");17 }18 }19 ArrayList al = new ArrayList();//存储输入流的集合对象
20 FileInputStream inputStream = null;//根据源文件的个数实例化输入流对象,因需要循环源文件数量,所以此处实例为null
21 File file = null;//源文件名字不一样,所以此处实例化为null
22 for (int i = 1; i <= cutFileCount; i++) {23 file = new File(dir, i + ".part");//源文件名
24 inputStream = new FileInputStream(file);//封装输入流对象
25 al.add(inputStream);//将输入流对象添加到流集合对象中
26 }27 Enumeration enu = java.util.Collections.enumeration(al);//从输入流集合对象中获取Enumeration对象以便传给序列流SequenceInputStream
28 SequenceInputStream sis = new SequenceInputStream(enu);//封装序列流对象
29 BufferedInputStream bis = new BufferedInputStream(sis);//缓冲输入流对象
30 File dest = new File(dir, fileName);//封装合并全的文件名及路径
31 FileOutputStream outputStream = new FileOutputStream(dest);//输出流对象
32 BufferedOutputStream bos = new BufferedOutputStream(outputStream);//输出缓冲对象33 //以下代码是循环读取及写入流对象,关闭流
34 intlen;35 while ((len = bis.read()) != -1) {36 bos.write(len);37 }38 bos.close();39 bis.close();40 }