英雄有泪

欲学惊人艺,须下苦功夫,深功出巧匠,苦练出真功。

导航

黑马程序员_Java基础:IO流总结

      IO流在是java中非常重要,也是应用非常频繁的一种技术。初学者要是能把IO技术的学透,java基础也就能更加牢靠。本文是根据以前学习IO的过程中的一些总结,再通过查找资料完善出来的,应该算是比较适合初学者解读的。

一、概念

      流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输。所以,为了方便更直观的进行数据操作,就根据数据传输特性将流抽象为各种类。

      一个流,必有源端和目的端,它们可以是计算机内存的某些区域,也可以是磁盘文件,甚至可以是Internet上的某个URL。

      流的方向是重要的,根据流的方向,流可分为两类:输入流和输出流。用户可以从输入流中读取信息,但不能写它。相反,对输出流,只能往输入流写,而不能读它。

      我们可以把形象的比喻成水流 ,文件和程序之间连接一个管道,水流就在之间形成了,自然也就出现了方向:可以流进,也可以流出。

 

二、流的分类

      1.根据从流本身的特点来说,可以分为结点流(node stream)过滤流(filters)

      (1)结点流直接从指定的位置(如磁盘文件或内存区域)读或写。(如FileOutputStream和FileInputstream)
  (2)过滤流输入流往往是以其它输入流作为它的输入源,经过过滤或处理后再以新的输入流的形式提供给用户,过滤流输出流的原理也类似。(如ObjectOutputStream和ObjectInputStream)

 

      2.根据流操作对象的类型是字节还是字符可分为两大类: 字节流和字符流。

      (1)字节流,顾名思义,是操作字节的流,而字节也是最基本的存储单位,所以字节流是最基本的流。它对应有字节输入流和字节输出流(InputstreamOutputStream)。
  (2)字符流,是操作字符的流。我们应该知道,字符是从字节根据编码表编码而来的,而编码表不是唯一的,这就造成了同样的字节数据,如果根据的编码表不一样,那么最终得到的字符也就不一样。所以为了对字符进行高效操作,就有了字符流。总的来说,字符流本质上是基于字节流读取时,查询了指定的码表。字符流也对应有字符输入流和字符输出流(Reader和Writer)。

 

      字节流和字符流的区别可以归纳一下:

      (1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
      (2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
      (3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件。

 

三、一般使用原则

      java类库中,还包含很多流对象,我们可以看一下他们的派生关系,如下图示意:

      那么,这么多的流对象,使用中如何选择?

      我们先把流对象按特点划分一下:

      1.按数据来源和目的:   
      (1)是文件: FileInputStream, FileOutputStream, FileReader, FileWriter   
      (2)是byte[]:ByteArrayInputStream, ByteArrayOutputStream   
      (3)是Char[]: CharArrayReader, CharArrayWriter  
      (4)是String: StringBufferInputStream, StringReader, StringWriter  
      (5)网络数据流:InputStream, OutputStream, Reader, Writer  
 
      2.按是否格式化输出:  
      要格式化输出:PrintStream, PrintWriter  
 
      3.按是否要缓冲:  
      要缓冲:BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter  
 
      4.按数据格式:  
      (1)二进制格式(只要不能确定是纯文本的): InputStream, OutputStream及其所有带Stream结束的子类  
      (2)纯文本格式(含纯英文与汉字或其他编码方式);Reader, Writer及其所有带Reader, Writer的子类  
 
      5.按输入输出:  
      (1)输入:Reader, InputStream类型的子类  
      (2)输出:Writer, OutputStream类型的子类  
 
      6.特殊需要:   
      (1)从Stream到Reader,Writer的转换类:InputStreamReader, OutputStreamWriter   
      (2)对象输入输出:ObjectInputStream, ObjectOutputStream  
      (3)进程间通信:PipeInputStream, PipeOutputStream, PipeReader, PipeWriter   
      (4)合并输入:SequenceInputStream   
      (5)更特殊的需要:PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader

 

      基于以上各个流的特点,我们在使用IO流时,可按一下步骤判断选择:

      (1)考虑最原始的数据格式是什么:是否为文本?
  (2)是输入还是输出?
  (3)是否需要转换流:InputStreamReader, OutputStreamWriter?
  (4)数据来源和目的是什么:文件?内存?网络?
  (5)是否要缓冲:bufferedReader等 ?
  (6)是否要格式化输出:print?

 

四、应用

1.例子一(字节流复制图片):

 1 import java.io.FileInputStream;
 2 import java.io.FileOutputStream;
 3 import java.io.IOException;
 4 
 5 /*
 6 要求:复制一张图片。
 7 
 8 需求分析:
 9 1,原始的数据格式是什么:是否为文本?
10 原始数据是图片,所以用字节流。
11 2,是输入还是输出? 
12 需要复制,所以需要输入和输出。
13 3,是否需要转换流?
14 因为操作过程中只涉及字节,所以不需要转换流。
15 4,数据来源和目的是什么:文件?内存?网络?
16 数据源是硬盘,写入目的地也是硬盘。所以使用FileInputStream和FileOutputStream。
17 5,是否要缓冲?
18 不需要使用缓冲。
19 6,是否要格式化输出?
20 不需要格式化输出。
21 
22 思路:
23 1,用字节读取流对象和图片关联。
24 2,用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。
25 3,通过循环读写,完成数据存储。
26 4,关闭资源。
27  */
28 public class CopyPicTest {
29 
30     public static void main(String[] args) {
31         FileOutputStream fos = null;
32         FileInputStream fis = null;
33         
34         try
35         {
36 //            定义读取和写入目的文件。如果文件在多层路径下,可以先定义File。
37             fos = new FileOutputStream("d:\\Miku_Toxic_Copy.jpg");
38             fis = new FileInputStream("c:\\Miku_Toxic.jpg");
39             
40             byte[] buf = new byte[1024*4];  //先把字节写入到字节数组中。
41             int len = 0;
42             
43             while ((len=fis.read(buf))!=-1)
44             {
45                 fos.write(buf,0,len);    //再把字节数组中的元素写入目的文件。
46             }
47         }
48         catch (IOException e)
49         {
50             throw new RuntimeException("复制文件失败");
51         }
52         finally
53         {
54             try
55             {
56                 if(fis!=null)
57                     fis.close();
58             }
59             catch (IOException e1)
60             {
61                 throw new RuntimeException("读取关闭失败");
62             }
63             
64             try
65             {
66                 if(fos!=null)
67                     fos.close();  // 流使用完必须要关闭,释放系统资源。在finally块中关闭就是为了保证执行关闭动作。
68             }
69             catch (IOException e1)
70             {
71                 throw new RuntimeException("写入关闭失败");
72             }
73         }
74     }
75 }

      需要注意的是,任何流最终都必须要关闭,释放系统资源。所以可以把关闭资源的动作,放在fially块中来保证执行。

 

2.例子二(字符流复制文本文件):(为了方便阅读异常做抛处理)

 1 import java.io.BufferedReader;
 2 import java.io.BufferedWriter;
 3 import java.io.FileReader;
 4 import java.io.FileWriter;
 5 import java.io.IOException;
 6 /*
 7 要求:复制文本文件。
 8 
 9 需求分析:
10 1,原始的数据格式是什么:是否为文本?
11 原始数据是文本文件,所以用字符流。
12 2,是输入还是输出? 
13 需要复制,所以需要输入和输出。
14 3,是否需要转换流?
15 因为操作过程中只涉及字符,所以不需要转换流。
16 4,数据来源和目的是什么:文件?内存?网络?
17 数据源是硬盘,写入目的地也是硬盘。所以使用FileReader和FileWriter。
18 5,是否要缓冲?
19 有和没有缓冲的情况都有。
20 6,是否要格式化输出?
21 不需要格式化输出。
22  */
23 public class CopyFileTest {
24 
25     public static void main(String[] args) throws IOException{
26         readAndWriteFile_1();
27         readAndWriteFile_2();
28         readAndWriteFile_3();
29     }
30     
31     public static void readAndWriteFile_1()throws IOException
32     {
33         FileReader fr = new FileReader("c:\\fr.txt");
34         FileWriter fw = new FileWriter("d:\\fw1.txt");
35         
36         int ch = 0;        
37         while ((ch=fr.read())!=-1) {    //读一个字符,写一个字符。
38             fw.write(ch);
39             fw.flush();        //字符流写入时,需要刷新。
40         }
41 //        流使用完,必须要关闭。
42         fr.close();
43         fw.close();
44     }
45     
46     public static void readAndWriteFile_2() throws IOException
47     {
48         FileReader fr = new FileReader("fos.txt");
49         FileWriter fw = new FileWriter("d:\\fos2.txt");
50         
51         char[] cha = new char[1024];        //先把字符写入到字符数组中。
52         int len = 0;
53         while ((len=fr.read(cha))!=-1) {
54             fw.write(cha,0,len);    //再把字符数组中的元素写入目的文件。
55             fw.flush();        //字符流写入时,需要刷新。
56         }
57 //        流使用完,必须要关闭。
58         fr.close();
59         fw.close();
60     }
61     
62     public static void readAndWriteFile_3() throws IOException
63     {
64         FileReader fr= new FileReader("fos.txt");
65         FileWriter fw = new FileWriter("d:\\fos3.txt");
66 //        使用缓冲区。
67         BufferedReader bufr = new BufferedReader(fr);
68         BufferedWriter bufw = new BufferedWriter(fw);
69         
70         String len = null;
71         while ((len=bufr.readLine())!=null) {    //每次把文本中的一行读进缓冲区(不含换行符)。
72             bufw.write(len);    //再把一行数据写入目的文件(不含换行符)。
73             bufw.newLine();        //换行方法。
74             bufw.flush();        //字符流需要刷新。
75         }
76 //        流使用完,必须要关闭。
77         bufr.close();
78         bufw.close();
79     }
80 }

      前面有提过,字符流本身实际有使用缓冲技术,所以写入的时候需要手动刷新,让缓冲区的数据(内存)刷新到目的地。

 

3.例子三(转换流,将键盘录入数据保存为文本文件)

 1 import java.io.BufferedReader;
 2 import java.io.BufferedWriter;
 3 import java.io.FileWriter;
 4 import java.io.IOException;
 5 import java.io.InputStreamReader;
 6 /*
 7 要求:录入键盘数据,保存到文本文件。
 8 
 9 需求分析:
10 1,原始的数据格式是什么:是否为文本?
11 源数据是字节流。目的数据是字符流。
12 2,是输入还是输出? 
13 需要读取和写入,所以需要输入和输出。
14 3,是否需要转换流?
15 因为操作过程中有字节和字符,需要转换流。
16 4,数据来源和目的是什么:文件?内存?网络?
17 数据源是键盘录入,写入目的地是硬盘。所以使用InputStreamReader和FileWriter。
18 5,是否要缓冲?
19 需要。使用BufferedReadr和BufferedWriter。
20 6,是否要格式化输出?
21 不需要格式化输出。
22 */
23 public class TransStream {
24 
25     public static void main(String[] args) {
26         System.out.println("请输入要保存到文件中的内容(输入over结束):");
27 //        System.in录入键盘数据得到的是字节流,如要用字符流的方式读取,必须要先将字节流转成字符流。
28         InputStreamReader isr = new InputStreamReader(System.in);
29 //        使用缓冲区读写更加效率。
30         BufferedReader bufr = new BufferedReader(isr);
31         BufferedWriter bufw = null;
32         try {
33 //            也可以通过OutputStreamWriter来指定编码表。
34 //            bufw = new BufferedWriter(new OutputStreamWriter("c:\\systemin.txt","UTF-8"));    
35             bufw = new BufferedWriter(new FileWriter("c:\\systemin.txt"));            
36             String str = null;
37             while ((str=bufr.readLine())!=null) {
38                 if ("over".equals(str))
39                     System.exit(0);        //如果键盘录入over,则结束。
40                 bufw.write(str);
41                 bufw.newLine();
42                 bufw.flush();            
43             }
44         } catch (IOException e) {            
45             throw new RuntimeException("找不到目标文件或写入数据失败");
46         } finally {
47             try {
48                 if (bufw!=null) {
49                     bufr.close();
50                     bufw.close();
51                 }
52             } catch (IOException e) {                
53                 throw new RuntimeException("关闭资源失败");
54             }
55         }
56     }
57 }

      从以上例子可以看出,转换流是字符流和字节流之间的桥梁,我们实际也可以利用转换流把文本文件中的内容打印到控制台上。也就是说可以通过转换流让字符流和字节流相互转换。

      另外要注意的是,将字节转换成字符的时,想按照指定的码表来转换,也可以通过OutputStreamWriter(OutputStream out,CharsetEncoder enc)的方式指定,其中enc即代表码表的名字,如"UTF-8","ISO 8859-1"等。

 

4.例子四(利用打印流把键盘录入数据保存到文件):

 1 import java.io.BufferedReader;
 2 import java.io.FileWriter;
 3 import java.io.IOException;
 4 import java.io.InputStreamReader;
 5 import java.io.PrintWriter;
 6 /*
 7 要求:录入键盘数据,保存到文本文件。
 8 
 9 需求分析:
10 1,原始的数据格式是什么:是否为文本?
11 源数据是字节流。目的数据是字符流。
12 2,是输入还是输出? 
13 需要读取和写入,所以需要输入和输出。
14 3,是否需要转换流?
15 因为操作过程中有字节和字符,需要转换流。
16 4,数据来源和目的是什么:文件?内存?网络?
17 数据源是键盘录入,写入目的地是硬盘。所以使用InputStreamReader和FileWriter。
18 5,是否要缓冲?
19 需要。使用BufferedReadr。
20 6,是否要格式化输出?
21 需要格式化输出。使用PrintWriter。
22 */
23 public class PrintStream {
24 
25     public static void main(String[] args) throws IOException{
26         BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
27 //        PrintWriter可以设置刷新模式,如果刷新模式为true,那么PrintWriter部分方法输出是会自动刷新。
28         PrintWriter out = new PrintWriter(new FileWriter("c:\\a.txt"),true);
29         String line = null;
30         while ((line=bufr.readLine())!=null)
31         {
32 //            如果键盘输入over,则结束程序。
33             if("over".equals(line))
34                 break;
35 //            因为PrintWriter设置有刷新模式,不需再手动刷新。
36             out.println(line.toUpperCase());
37         }
38         bufr.close();
39         out.close();
40     }
41 }

      看完例子,在看看打印流的特点:

      打印流:
      该流提供了打印方法,可以将各种数据类型的数据都原样打印。

      字节打印流:
      PrintStream
      构造函数可以接收的参数类型:
      (1)file对象。File
      (2)字符串路径。String
      (3)字节输出流。OutputStream

      字符打印
      PrintWriter
      构造函数可以接收的参数类型:
      (1)file对象。File
      (2)字符串路径。String
      (3)字节输出流。OutputStream
      (4)字符输出流。Writer

 

      可以看出,字符打印流相对来说适用性更强。

 

5.例子五(LineNumberReader):

 1 import java.io.FileReader;
 2 import java.io.IOException;
 3 import java.io.LineNumberReader;
 4 
 5 public class LineNumberReaderDemo {
 6     public static void main(String[] args)throws IOException {
 7         FileReader fr = new FileReader("PersonDemo.java");
 8 
 9         LineNumberReader lnr = new LineNumberReader(fr);
10 
11         String line = null;
12         lnr.setLineNumber(100);
13         while((line=lnr.readLine())!=null)
14             System.out.println(lnr.getLineNumber()+":"+line);
15         lnr.close();
16     }
17 }

      从以上例子可以看出,LineNumberReader属于过滤流,而它实际的功能也是在字符写入流的基础上,加上获取行号(getLineNumber()), 设置行号(setLineNumber())的功能。LineNumberOutputStream同理,这里不再做阐述。

 

6.例子六(数据流):

 1 import java.io.DataInputStream;
 2 import java.io.DataOutputStream;
 3 import java.io.FileInputStream;
 4 import java.io.FileOutputStream;
 5 import java.io.IOException;
 6 
 7 public class DataStreamDemo 
 8 {
 9     public static void main(String[] args) throws IOException{
10         writeData();
11         readData();
12     }
13 
14     public static void readData()throws IOException{
15         DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
16 
17         int num = dis.readInt();
18         boolean b = dis.readBoolean();
19         double d = dis.readDouble();
20 
21         System.out.println("num="+num);
22         System.out.println("b="+b);
23         System.out.println("d="+d);
24 
25         dis.close();
26     }
27     public static void writeData()throws IOException{
28         DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
29 
30         dos.writeInt(234);
31         dos.writeBoolean(true);
32         dos.writeDouble(9887.543);
33 
34         dos.close();
35     }
36 }

以上运行结果是:

234
true
9887.543

 

      从例子可以看出数据流的特点:

      DataInputStreamDataOutputStream,经常用来处理基本数据类型的数据,好处就是可以按类型来处理数据。

 

7.例子七(数组流):

 1 import java.io.ByteArrayInputStream;
 2 import java.io.ByteArrayOutputStream;
 3 
 4 public class ByteArrayStream {
 5     public static void main(String[] args) {
 6         //数据源。
 7         ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".getBytes());
 8         //数据目的,数组输出流输出的数据目的地是内存。
 9         ByteArrayOutputStream bos = new ByteArrayOutputStream();
10 
11         int by = 0;
12         while((by=bis.read())!=-1)
13             bos.write(by);
14 
15         System.out.println(bos.size());
16         System.out.println(bos.toString());
17 
18 //        最后内存中流的数据可以通过writeTo方法输出到其他节点流中,将数据保存到目的地。
19     //    bos.writeTo(new FileOutputStream("a.txt"));
20     }
21 }

运行结果为:

7
ABCDEFD

 

      数组流是用于操作字节数组的流对象,它是使用流的思想来操作数据的体现。
      ByteArrayInputStream :在构造的时候,需要接收数据源,而且数据源是一个字节数组。
      ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是数据目的地(在内存中)。
      因为这两个流对象都操作的数组,并没有使用系统资源。
      所以,不用进行close关闭。

 

8.例子八(RandomAccessFile):

 1 import java.io.IOException;
 2 import java.io.RandomAccessFile;
 3 
 4 public class RandomAccessFileDemo {
 5     public static void main(String[] args) throws IOException{
 6         writeFile();
 7         writeFile_2();
 8         readFile();
 9     }
10 
11     public static void readFile()throws IOException{
12         RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
13         //调整对象中指针,以8为单位是因为两个中文字4个字节加上int数据的4个字节。
14         //raf.seek(8*1);
15 
16         //跳过指定的字节数
17         raf.skipBytes(8);
18 
19         byte[] buf = new byte[4];
20         raf.read(buf);
21         String name = new String(buf);
22         int age = raf.readInt();
23 
24         System.out.println("name="+name);    //结果为周七。
25         System.out.println("age="+age);
26         raf.close();
27     }
28 
29 //    也能修改指定指针上的数据。
30     public static void writeFile_2()throws IOException{
31         RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
32         raf.seek(8*0);
33         raf.write("周七".getBytes());
34         raf.writeInt(103);
35         raf.close();
36     }
37 
38     public static void writeFile()throws IOException{
39         RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
40         raf.write("李四".getBytes());
41         raf.writeInt(97);
42         raf.write("王五".getBytes());
43         raf.writeInt(99);
44         raf.close();
45     }
46 }

运行结果为:

周七
103

 

      从前面的派生图可以看出,RandomAccessFile不算是IO体系中子类,而是直接继承自Object。但是它是IO包中成员,因为它具备读和写功能。
      实际上RandomAccessFile内部封装了一个数组,而且通过指针对数组的元素进行操作。
      从例子可以看出通过getFilePointer获取指针位置,同时通过seek改变指针的位置。
      至于RandomAccessFile能够同时实现读和写的功能的原因,其实是是其在内部封装了字节输入流和输出流。
      通过查询API中构造函数可以看出,该类只能操作文件,而且操作文件还有模式:只读r,,读写rw等。
      如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
      如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。

 

9.例子九(管道流):

 1 import java.io.IOException;
 2 import java.io.PipedInputStream;
 3 import java.io.PipedOutputStream;
 4 
 5 class Read implements Runnable {
 6     private PipedInputStream in;
 7     Read(PipedInputStream in){
 8         this.in = in;
 9     }
10     public void run() {
11         try {
12             byte[] buf = new byte[1024];
13 
14             System.out.println("读取前。。没有数据阻塞");
15             int len = in.read(buf);
16             System.out.println("读到数据。。阻塞结束");
17 
18             String s= new String(buf,0,len);
19             System.out.println(s);
20             in.close();
21         }
22         catch (IOException e) {
23             throw new RuntimeException("管道读取流失败");
24         }
25     }
26 }
27 
28 class Write implements Runnable {
29     private PipedOutputStream out;
30     Write(PipedOutputStream out) {
31         this.out = out;
32     }
33     public void run() {
34         try {
35             System.out.println("开始写入数据,等待6秒后。");
36             Thread.sleep(6000);
37             out.write("piped lai la".getBytes());
38             out.close();
39         }
40         catch (Exception e) {
41             throw new RuntimeException("管道输出流失败");
42         }
43     }
44 }
45 
46 public class  PipedStreamDemo {
47     public static void main(String[] args) throws IOException {
48         PipedInputStream in = new PipedInputStream();
49         PipedOutputStream out = new PipedOutputStream();
50 //        管道输入流连接到管道输出流。
51         in.connect(out);
52 
53         Read r = new Read(in);
54         Write w = new Write(out);
55         new Thread(r).start();
56         new Thread(w).start();
57     }
58 }

运行结果为:

读取前。。没有数据阻塞
开始写入数据,等待6秒后。
读到数据。。阻塞结束
piped lai la

 

      看完例子,再来看看管道流的特点:

      PipedInputStream类与PipedOutputStream类用于在应用程序中创建管道通信,多用于多线程中。

      一个PipedInputStream实例对象必须和一个PipedOutputStream实例对象进行连接而产生一个通信管道。PipedOutputStream可以向管道中写入数据,PipedIntputStream可以读取PipedOutputStream向管道中写入的数据。

      这两个类主要用来完成线程之间的通信。一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据。

      所以,我们使用管道流时,必须要同时构造管道输入流和管道输出流。

 

10.例子十(合并流):

 1 import java.io.FileInputStream;
 2 import java.io.FileOutputStream;
 3 import java.io.IOException;
 4 import java.io.SequenceInputStream;
 5 import java.util.ArrayList;
 6 import java.util.Enumeration;
 7 import java.util.Iterator;
 8 
 9 public class MergeFile {
10     public static void main(String[] args) throws IOException {
11         merge();
12     }
13 
14     public static void merge() throws IOException {
15 //        创建集合,泛型为文件字节输入流。
16         ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
17 
18         for(int x=1; x<=3; x++)
19 //            将输入流添加进集合中。
20             al.add(new FileInputStream("c:\\splitfiles\\"+x+".part"));
21 
22         final Iterator<FileInputStream> it = al.iterator();
23 
24 //        因为前面为了更加让程序效率使用了ArrayList,所以这里只能通过匿名内部类自定义Enumeration,实现目的。
25 //        如果前面使用的是Vetor集合,则不需再定义这一步。
26         Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
27             public boolean hasMoreElements() {
28                 return it.hasNext();
29             }
30             public FileInputStream nextElement() {
31                 return it.next();
32             }
33         };
34 
35         SequenceInputStream sis = new SequenceInputStream(en);
36 
37         FileOutputStream fos = new FileOutputStream("c:\\splitfiles\\0.bmp");
38         byte[] buf = new byte[1024];
39         int len = 0;
40         while((len=sis.read(buf))!=-1)
41             fos.write(buf,0,len);
42 
43         fos.close();
44         sis.close();
45     }
46 }

      合并流,SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。总而言之,合并流就是用来合并多个字节输出流变成一个字节输出流。

 

11.例子十一(分割文件):

 1 import java.io.FileInputStream;
 2 import java.io.FileOutputStream;
 3 import java.io.IOException;
 4 
 5 public class SplitFile {
 6     public static void main(String[] args) throws IOException {
 7         splitFile();
 8     }
 9 
10     public static void splitFile()throws IOException {
11         FileInputStream fis =  new FileInputStream("c:\\1.bmp");
12         FileOutputStream fos = null;
13 
14         byte[] buf = new byte[1024*1024];
15         int len = 0;
16         int count = 1;
17         while((len=fis.read(buf))!=-1) {
18             fos = new FileOutputStream("c:\\splitfiles\\"+(count++)+".part");
19             fos.write(buf,0,len);
20             fos.close();
21         }         
22         fis.close();        
23     }
24 }

      可以看出,java中并没有可以直接分割流的对象。分割流的方法很多,以上例子主要是通过计数器,和作为缓冲区的数组来控制分割流,然后输出到不同的文件上。

 

      这十一个例子囊括了IO流中最常用的部分,剩余其他的流的使用思想也是相通的,这里就不再阐述了。相信只要认真的去了解学习IO流,以后它就会成为你的好帮手。

 

posted on 2015-08-01 22:44  丨敲破苍穹灬  阅读(269)  评论(0)    收藏  举报