对程序语言的设计者来说:创建一个好的输入/输出(I/O)系统是一项艰难的任务。原因有二:1.存在各种I/O源端和想要与之通信的接收端(文件,控制台,网络链接等),而且多种不同的方式与他们进行通信(顺序,随机存取,缓冲,二进制,按字符,按行,按字等);
IO>1:File类:
处理文件目录问题;
File这个类并非指代文件,实际上它既能代表一个特定文件的名称,也能代表一个目录下一组文件的名称;作为一个目录名称时,list()返回一个String[];之所以返回一数组而不是一个类容器,是因为目录下文件的个数是固定的;实际上,使用FilePath(文件路径)对这个类来说是个更好的名称;
aa.目录列表器;
list()获取此File对象的所有列表;如果想获取一个受限列表,例如,获取扩展名为.java的文件,使用”目录过滤器”
ab.目录实用工具;
操作文件时常常需要操作本地目录或者遍布于整个目录树中的文件集合,此处准备local产生本地目录中的文件构成的File对象目录,或者使用walk方法产生给定目录下的整个目录树中所有文件构成的List<File>(File对象比文件名更有用,因为File对象含有更多的信息);
ac.目录的检查和创建;
File不只代表存在的目录和文件,也可以用File对象来创建新的目录或者尚不存在的整个目录路径。我们还可以查看文件的特性(如:大小,最后修改日期,读/写),检查某个File对象检查代表的是一个文件还是一个目录,并可以删除文件;
IO.2>.输入输出系统
Java类库中的I/O分为输入/输出两部分;通过继承,任何自InputStream或者Reader派生的类都含有read的基本方法;任何自OutputStream或者Writer派生的类都含有write的基本方法;
按功能对I/O部分的分类:
InputStream的类型:
InputStream的作用是用来表示那些从不同数据源产生输入的类;这些数据源包括:
1) 字节数组; 2)String对象; 3)文件 4)管道 4)流序列 5)其他数据源;
除此之外,FilterInputStream作为一种InputStream,为装饰类提供基类;
class 功能 构造器参数/如何使用
ByteArrayInputStream 允许将内存的缓冲 缓冲区,字节从中取出;
区当做InputStream使用;
StringBufferInputStream 将String转为InputStream; 字符串,底层使用StringBfer;
FileInputStream 从文件中读取信息; 字符串,文件名等;
PipedInputStream 管道化概念 多线程中数据源;
SequenceInputStream 两个/多个InputStream对象 两个InputStream对象;
转成单一InputStream;
FilterInputStream 装饰类接口;
OutputStream类型:
字节数组(No String);文件和管道;FilterInputStream为“装饰类”提供了一个基类;
类 功能 构造器参数/使用
ByteArrayOutputStream 缓冲区初始化尺寸;
FileOutputStream 文件路径,文件或者FileDescriptor对象;
PipedOutputStream 多线程数据的目的地;
FilterOutputStream 装饰类接口
IO>3:添加属性和有用的接口:
装饰类使用的原因:
java I/O类库需要多种功能不同的组合;这是装饰模式和装饰类接口filter存在的原因;装饰器必须具有和它装饰的对象相同的接口,但它同时也可以扩展接口;
此处,FilterI/O都由I/O派生而来,这是它们可以作为装饰器的必要条件;
通过FilterInputStream从InputStream中读取数据:
FilterInputStream完成的两件不同的事情:其中DataInputStream允许我们读取不同的基本类型数据以及String对象,(所有的方法都以”read”开头,readByte(),readFloat等);搭配相应的DataOutputStream,就可以通过数据”流”将基本类型的数据从一个地方迁移到另一个地方;
其他的FilterInputStream类则在内部修改InputStream的行为方式:是否缓冲,是否保留它所读过的行,以及是否把单一字符推回输入流;
FilterInputStream类型:
类 功能 构造器参数/如何使用
DataInputStream 搭配DataOutputStream,可以 InputStream包含用于读取基本
按照可移植方式从流中读取基本 类型数据的全部接口;
的数据类型;(int ,char,long等)
BufferedInputStream 可防止每次读取都使用实际写 InputStream,可以指定缓冲区大小
代表”使用缓冲区”; (可选),本质上不提供接口,只不过是向
进程中添加缓冲区必须的;
LineNumberInputStream 跟踪输入流中的行号,可 InputStream:仅增加了行号,可能要
调用getLineNumber()和 和接口对象搭配使用;
setLineNumber(int);
PushbackInputStream 具有”能弹出一个字节的缓冲区” InputStream;
因此可以将读到的最后一个字节回退 通常作为编译器的扫描器;
通过FilterOutputStream向OutputStream中写入数据;
类 功能 构造器参数/使用
DataOutputStream 与DataInputStream搭配 OutputStream
PrintStream 格式化输出,DataOutputStream做 OutputStream
数据存储,PrintStream做显示;
BufferedOutputStream 避免每次发送数据的写操作;
flush清空缓冲区
IO>4:Reader&Writer
提供兼容Unicode与面向字符的I/O功能;
另外:a.java1.1中向InputStream和OutputStream继承层次结构中增加了一些新的类,所以InputStream和OutputStream不会被替代;
b.有时需要将面向字符的类和面向字节中的类结合起来,为此,使用适配器类:
InputStreamReader可以把InputStream转化为Reader;OutputStreamWriter可以把OutputStream转为Writer;
设计Reader和Writer的主要目的是为了国际化;
数据的来源和去处:
需要注意的是,在某些场合,面向字节的InputStream和OutputStream才是正确的解决方案,特别:java.util.zip类库就是面向字节的而不是面向字符的;
最明智的方式是尽量尝试使用Reader和Writer,程序无法编译成功时,再使用面向字符的类库;
比较如下:
java1.0 java1.1
InputStream Reader// InputStreamReader作为转换的适配器类
OutputStream Writer//OutputStreamWriter作为转换的适配器类
FileOutputStream FileWriter
FileInputStream FileReader
StringBufferInputStream(已弃用) StringReader
无相应的类 StringWriter
ByteArrayInputStream CharArrayReader
ByteArrayOutputStream CharArrayWriter
PipedInputStream PipedReader
PipedOutputStream PipedWriter
更改流的行为:
对于InputStream和OutputStream来说,我们使用FilterInputStream和FilterOutputStream的装饰器子类来修改”流”以满足特殊需求;Reader和Writer的类继承层次结构继续沿用相同的思想---并不完全相同;
下表中,对于前一表格来说,左右之间相互关系的对应关系之间的近似程度应该更加粗略一些,原因在于类的组织形式不同,尽管BufferedInputStream是FilterInputStream的子类,但是BufferedWriter不是FilterWriter的子类(FilterWriter可以看做是一个占位符类);
过滤器类 java1.0 1.1对应
FilterInputStream FilterReader
FilterOutputStream FilterWriter(抽象类,没有子类)
BufferedInputStream BufferedReader(也有 readLine())
BufferedOutputStream BufferedWriter
DataInputStream 使用DataInputStream(除了使用readLine-àBuffered)
PrintStream PrintWriter
LineNumberInputStream(已经弃用) LineNumberReader
StreamTokenizer StreamTokenizer(使用接受Reader的构造器)
PushbackInputStream PushbackReader
无论何时使用readLine,都不应该再使用DataInputStream,而应该使用BufferedReader,除了这一点,DataInputStream仍是I/O类库的首选成员;
为了更容易地过渡到使用PrintWriter,它提供了一个既能接受任何OutputStream又能接受Writer对象的构造器;
Java 5SE中增加了PrintWriter的构造器,以简化在输出写入时的文件创建过程,关于PrintWriter,有一种构造器中有个参数,如果不设置该项,在每个Println()执行后,都会清空;
未发生变化的类:
java1.0和java1.1中没有变化的类:DataOutputStream;File;
RandomAccessFile;SequeceInputStream;
IO.5>自我独立的类:RandomAccessFile;
适用于由大小已知的记录组成的文件;我们可以使用seek()将记录从一处转移到另外一处;然后读取和修改记录;文件中记录的大小不一定都相同;只要我们能够确定记录有多大,以及它们在文件中的位置即可;
RandomAccessFile除了实现了DataInput和DataOutput接口以外,和InputStream,OutputStream的继承层次没有任何关系;是一个完全独立的类,从头编写其所有的方法:我们可以使用RandomAccessFile在一个文件中向前或者向后移动;任何情况下,它都是自我独立的,直接由Object派生而来;
本质上,RandomAccessFile的工作方式类似把DataInputStream和DataOutputStream组合起来,还添加了一些其他方法;其中getFilePointer()用于查找当前所处文件位置;seek用于在文件内移至新的位置;length()判断文件的尺寸;构造器的第二个参数指示我们随机读(R)还是既读又写(RW);
只有RandomAccessFile支持搜寻方法;
JDK1.4中,RandomAccessFile的大多数功能(非全部)由nio的存储映射文件所代替;