IO流的介绍

系统 1371 0
对于任何程序设计语言而言,输入输出(I/O)系统是最复杂的一部分,因为通信的双方不仅仅是I/O源端和接收端,还可能是文件、网络链接或内存磁盘等,而且这些数据的数据格式多样,如字符、二进制、字节。Java通过创建大量的类库解决这个问题。
12.1  流(stream)的概念
Java的I/O系统涉及流的概念。一个读取字节序列的对象被称为输入流,一个可以写入字节序列的对象称为输出流。输出流和输入流是相对于程序本身而言的。程序读取数据称为打开输入流,程序向其他源写入数据称为打开输出流,该过程如图所示。

12.2  字符流
在Java的I/O系统提供了InputStream和OutputStream两个抽象类实现字节(8位)数据的输入输出,其中InputStream是输入流的抽象类,提供了read方法,各个实现了该类的子类都要实现该方法,如 ObjectInputStream类继承InputStream抽象类,重新定义了方法read()来读取字节数据。本节介绍抽象类 InputStream和OutputStream及其相对应的子类。
12.2.1 输入流类InputStream
抽象类InputStream表示从不同的输入源输入数据的类,这些数据源的数据类型多样,可以是字节数组、String对象、类的序列化对象,文件、管道或网络链接。对于多样的数据类型有相应的输入流类与其对应。下面介绍这些流类,使读者对这些类的功能和使用方式有基本的了解。
InputStream是个抽象类,提供了抽象read方法,下面几个类是继承自InputStream 的子类:
ByteArrayInputStream(字节数组输入流)
FileInputStream(文件输入流)
PipedInputStream(管道输入流)
SequenceInputStream(序列化输入流)
StringBufferInputStream(字符串缓冲输入流)
ObjectInputStream(对象输入流)
FilterInputStream(过滤器输入流)
以下的类继承自 FilterInputStream(过滤器输入流),同时实现了DataInput接口。
LineNumberInputStream(行号输入流)
DataInputStream(数据输入输入流)
BufferedInputStream(缓冲输入流)
PushbackInputStream(推回输入流)
12.2.2输出流类OutputStream
抽象类OutputStream是表示输出数据流的抽象类,与抽象输入流对应,提供各种流对象的数据输出。下面介绍的输出流类,可以使读者了解输出流类的功能和使用方式。
OutputStream是个抽象类,提供了抽象write方法,下面几个类是继承自InputStream的子类,这些类都实现了write()方法:
ByteArrayOutputStream(字节数组输出流类)
FileOutputStream(文件输出流类)
ObjectOutputSteam(对象输出流类)
PipedOutputStream(管道输出流类)
FilterOutputStream(过滤器输出流类)
下面三个类继承自FilterOutputStream类并实现了 DataOut接口。
DataOutputStream(数据输出流类)
BufferedOutputStream(缓冲输出流类)
PrintStream(打印输出流类)
12.3  字节流
Java在设计其I/O系统时,把输入输出的数据类型分为两类,一类是字符流,如上节介绍的InputStream 和OutputStream类及其子类都是处理字符(16bit)流。本节介绍字节(8bit)流,字节流也分为读流数据类和写流数据类,即Reader 类和Writer类及其子类。
12.3.1  Writer类
Writer类是字符(Character)流输出类的父类,它是抽象类,所有继承自该类的子类都必须实现抽象方法write,具体的实现类中write方法的使用可以参考相应的JavaDoc文档。这里为了区别InputStream和 OutputStream使用了Reader和Writer,为了使读者习惯于使用Reader和Writer,同时中文中没有合适的词汇表达相应的流的概念,所以不在具体翻译为中文,读者使用时只要知道Reader类负责读流数据,而Writer类负责向流中写数据。下面列出继承自Writer类的子类。
BufferedWriter(带缓冲Writer)
CharArrayWriter(字符数组Writer)
FilterWriter(带过滤器 Writer)
PrintWriter(打印Writer)
PipedWriter(管道Writer)
StringWriter(字符串Writer)
OutputStreamWriter(输出流Writer)
12.3.2  Reader类
Reader类是读取字符(Character)流的父类,它是抽象类,所有继承自该类的子类都必须实现抽象方法read和close,具体的实现类中read方法的使用可以参考相应的JavaDoc文档。下面列出继承自Reader类的子类。
BufferedReader(带缓冲Reader)
CharArrayReader(字符数组Reader)
FileReader(文件Reader)
FilterReader(过滤器Reader)
InputStreamReader(输入流Reader)
LineNumberReader(带行号Reader)
PipedReader(管道Reader)
PushbackReader(推回Reader)
StringReader(字符串Reader)
12.4  File类
File类最初看起来仿佛是代表文件,其实这点Java为该类起名确实有迷惑读者的地方,其实File类可以表示特定文件名(带绝对路径),也可以是某个目录下多一组文件,该类提供了方法可以用来访问多个文件。File类提供了丰富的方法来处理和文件或目录相关的操作。如创建和删除文件、创建和删除文件夹、通过和其他类配合使用实现文件的复制和移动等。本节将介绍File类提供的这些功能。
12.4.1  创建文件夹(目录)
File类提供了丰富的接口函数供用户调用。创建目录是文件操作中经常遇到的情形,目录提供了文件存放的位置,用户可以根据需要在磁盘空间上建立目录。建立目录的方法是调用mkdir()方法,代码为创建文件夹程序示例。

12.4.2  创建文件
在Java的File类中创建新文件只需要调用该类的一个方法createNewFile(),但是在实际操作中需要注意一些事项,如判断文件是否存在,以及如何向新建文件中写入数据等。代码创建文件示例演示了上述讨论的问题。该程序首先创建一个用户指定名称和类型的数据,并向文件中写书数据。

12.4.3  复制文件
文件的复制设计到文件流的概念,在下节将更详细的介绍文件流操作,本节为了实现文件操作,使用了 FileInputStream和FileOutputStream两个流类。通过文件输入流读取源文件,通过文件输入流把读入缓冲区的字节数据写入新文件,如果该新文件已经存在则覆盖掉该文件如果不存在则新建一个文件, 代码为复制文件程序示例。

12.4.4  删除文件
在Java的File类中删除文件只需要调用该类的一个方法delete(),该方法可以删除指定的文件。代码删除文件程序说明了该方法的具体使用方式。在程序执行时,用户给出要删除的文件的目录和文件名或文件夹,就可以完成删除操作。

12.4.5  删除文件夹
在Java的File类中删除文件夹需要首先删除掉文件夹中的文件,再删除空文件夹,删除空文件夹的方法与删除文件的方法相同,所以关键是如何实现删除文件夹下的所有文件。上面已经知道如何删除一个文件,可以想象欲删除一个目录下的所有文件只要获得该文件的目录和文件名,使一个循环调用来依次删除文件夹中的文件即可。代码12-9就是依照这种思路实现了删除文件夹中的多个文件并删除文件夹。
该类提供了两个方法,一个方法是删除文件夹,另一个是删除文件夹下的文件。如果在删除文件夹时,既有目录又有文件,则删除文件,再继续删除文件夹,如果该文件夹下还是既有文件又有文件夹则继续上面的操作,直到把目录下的文件和子目录全部删除。该过程的流程图如图所示。
12.5  I/O流的典型运用
通过12.3节和12.4节的内容知道整个I/O类库提供了两类流,一种是字符流,所有处理该字符(Character)型数据的输入输出流类都继承自InputStream和OutStream。一种是字节(Byte)流,所有处理字节流数据的输入输出流类都继承自Reader和Writer类。
本节介绍JavaI/O的几类典型应用,包括处理字节流和字符流数据。
12.5.1  文件流
文件流操作的目的是实现文件之间的数据传输,把数据从一个文件复制到另一个文件。文件的输入流可以是流类的对象如:FileReader,FileInputStream。文件的输入流是一个流类的对象如:FileWriter,FileOutputStream。 通过在文件上建立流,来实现文件间的数据传输。代码文件流操作示例,展示了如何通过这些流类实现文件的复制。

12.5.2  读取内存数据
在Java的输入输出流中 提供了读取内存数据的类,这些类包括StringReader和StringWriter、CharArrayReader和 CharArrayWriter、ByteArrayInputStream和ByteArrayOutputStream。在内存中读写数据通常是在已经存在的数组中创建I/O流。本节以StringReader和StringWriter为例,这两个类用于从内存中的一个字符串中读写数据。首先看代码读内存数据示例。

12.5.3  链接文件
Java提供SequenceInputStream类把多个输入流链接起来放在一个输入流中。多个输入流可以存入 Enumeration对象。将依次读取每个流对象内的数据,直到最后一个流对象的结尾。也可以直接链接两个输入流。这通过构造函数实现。代码就是链接文件的例子,首先创建两个输入流,再直接链接这两个输入流,打印到控制台输出,代码创建RMI服务器程序示例。

12.5.4  管道流
两种管道流,一种是通过PipedInputStream和PipedOutputStream实现,一种是通过PipedReader和PipedWriter实现。
管道流是对应多线程的概念,实现线程间通信,它建立在两个线程之上,它的实现原理是在管道的一端读入数据,而在管道的另一端读出输入。实现管道流时,关键是在线程中建立管道。体现在下面两行关键语句中。
PipedWriter pipeOut = new PipedWriter();
PipedReader pipeIn = new PipedReader(pipeOut);
12.5.5  随机访问文件
类RandomAccessFile实现文件的随机访问,可以在文件的任意位置读取或写入数据。该类与 InputStream和OutputStream不同。它把输入输出放入同一个类中,通过构造函数的参数确定是输入还是输出或输入输出操作可同时实现。该类的构造函数有两个参数,第一个参数是文件目录,第二个参数指定相应的操作,“r”读,“rw”读写。
RandomAccessFile in = new RandomAccessFile(“readme.txt”,”rw”);
RandomAccessFile in = new RandomAccessFile(“readme.txt”,”r”);
12.5.6  从标准输入读取
按照标准I/O模型,Java 提供了标准的输入输出方式,而System.out是经过包装的流对象,可以将数据写出到标准输出,但是System.in无法直接实现数据输入,因为 System.in是没有包装的流,所以在读取标准输入前必须对System.in进行包装。
在代码中用InputStreamReader来包装System.in成Reader,再包装成BufferedReader,先从标准输入读数据放入缓存,再从缓存中读出数据赋予变量s,最后从变量 s中读取数据在屏幕上输出。

12.5.7  I/O重定向
I/O重定向是指把标准输入定向到一个文件,把这个文件作为程序输入源,而把数据输出到一个指定的文件。因为I/O操纵的是字节流,所以采用InputStream和OutputSteam流类族实现输入输出重定向。
12.5.8  过滤流
按照标准I/O模型,Java 提供了标准的输入输出方式,而System.out是经过包装的流对象,可以将数据写出到标准输出,但是System.in无法直接实现数据输入,因为 System.in是没有包装的流,所以在读取标准输入前必须对System.in进行包装。
代码中用InputStreamReader来包装 System.in成Reader,再包装成BufferedReader使用。

12.5.9  序列化对象
对象的序列化后的输入输出通过ObjectInputStream和ObjectOutputStream 类实现。序列化的本质是把具有一定结构的Java对象进行打包,而后通过特定的输入输出流来处理。本节将学习使用Java提供的对象输入输出类来实现序列化对象的传输。
类ObjectInputStream和ObjectOutputStream不能单独使用,必须附加在其他流之上,对其他输入输出流进行包装,因为对象的输入输出必须对应一个存储对象的文件,这里采用文件输入输出流对象作为对象输入输出流对象的参数来构造对象输入输出流对象,实现对象在文件之间的传输。OjbectInputStream类提供了各种read方法读取特定类型的数据,如readObject()、 readInt()、readBoolean()等方法读取流中的对象。OjbectOutputStream类提供了各种write()方法读取特定类型的数据,如writeObject()、writeInt()、writeBoolean()等方法向流中的写入数据。
12.6  习题
(1)选择题
1.Java I/O流按处理的数据类型分为哪两类:
A.比特流和字符流  B.比特流和字节流
C.字符流和字节流  D.管道流和过滤流
2.实现多线程间通信使用的流是:
A.Object Stream  B.Random Access Stream
C.File Stream  D.Piped Stream
3.为了读取或修改一个文件的指定位置的数据,需要使用的流是:
A.Object Stream  B.Random Access Stream
C.Filter Stream  D.Piped Stream
4.有一个对象需要传输给另一个程序,此时考虑使用的流是:
A.Object Stream  B.Random Access Stream
C.File Stream  D.Piped Stream
5.常用的对读取文件数据的流是:
A.Object Stream  B.Random Access Stream
C.File Stream  D.Piped Stream
6.如果需要把多个输入流合并到一个输入流的是:
A.Object Stream  B.Sequence object Stream
C.File Stream  D.Piped Stream
(2)简答题
1.解释I/O重定向的含义和设计到的输入输出类。
2.过滤流的功能以及设计到的类。
3.将多个输入流合并到一个输入流的类为 SequenceObjectStream,解释该类的两个构造函数。
4.参考JavaDoc文档,查看File类的各种方法,做到熟练使用文件的各种操作。
(3)编程题
1.参考12.5.1编写一个类,该类可以读取自己的.java文件,把该文件存储到一个.xls文件中,并在控制台打印文件内容。
2.改写12.5.3节的示例程序,调用SequenceInputStream的另一个构造函数实现多个(大于2个)文件的链接任务,该构造函数形式为SequenceInputStream(Enumeration enu)。

IO流的介绍


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论