Java核心技术:卷1笔记[10] 流与文件

来源:互联网 发布:网络谐音词大全 编辑:程序博客网 时间:2024/06/07 17:34
 

1.保存在文件中的信息,或者从一个网络连接中获取的信息,其处理方式在本质上是完全一样的。可以从中读出一系列字节的对象称为输入流,能向其中写入一系列字节的对象称为输出流。这两种对象分别用抽象类InputStream和OutputStream来实现。对于以Unicode格式来保存的信息来说,用以字节为基础的流来处理不是很方便,因此,专门处理Unicode的类都从抽象类Reader和Writer继承而来。

2.InputStream类提供了一个抽象方法:abstract int read(),该方法会读取一个字节并返回,假如遇到输入流的结尾,就返回-1.类似的,OutputStream类定义了抽象方法:abstract void write(int b)用来将一个字节写到指定的输出位置。无论read方法还是write方法都会阻塞线程的运行,直到字节被实际读出或写入为止。可以调用System.in.available()方法检查目前能够读取的字节数,再进行读取操作以避免线程挂起。InputStream类也提供了非抽象方法,这些方法会调用抽象的read方法,这样其子类只需要覆盖一个方法就可以了。

3.完成了对流的读取或写入操作后,要使用close方法将其关闭,该方法会释放流所占得资源,同时也会刷新输出流使用的缓冲区。如果没有关闭一个文件,很可能最后一个字节包永远你不会被投递出去,当然也可以用flush方法来主动刷新输出缓冲。

4.Java提供了总数超过60种的流类,均是从基本的InputStream和OutputStream类衍生出来的。利用这些类可以操作常见格式的数据,而不必操作那些低级别的字节流。

5.流过滤器的分层:对某些流来说,可以从文件或者其他地方读入字节,而对另一些流来说,它们则可将字节组装成更有用的数据类型。Java程序员通过将一个现成的流传递给另一个流的构造器来综合运用这两种流,将其合并成所谓“过滤流”。例如为了能从文件中读取数字,首先要创建一个FileInputStream,然后将其传递给一个DataInputStream的构造器:

       FileInputStream fin=new FileInputStream(“employee.dat”);

       DataInputStream din=new DataInputStream(fin);

       double s=din.readDouble();

6.有时候将多个中间流串连到一起时,需要对它们进行跟踪,例如在读取输入时提前检查下一个字节,看看是否是希望的值,为此可利用PushbackInputStream来实现:

       PushbackInputstream pbin=new

                            PushbackInputstream(new BufferedInputStream(new FileInputStream(“employee.dat”)));

       int b=pbin.read();

       if(b!’<’) pbin.unread(b);

       如果想在“向前看”的同时也能读入数字,就同时需要一个pushback输入流以及一个数据输入引用流:

       PushbackInputstream pbin;

       DataInputStream din=new DataInputStream(

                                          pbin= new PushbackInputstream(new

                                                  BufferedInputStream(new

                                                        FileInputStream(“employee.dat”))));

7.数据流:数据流因为实现了DataOutput、DataInput接口,因此可以读取或写入全部基本Java类型。如DataOutput接口提供下列方法:writeChars、writeByte…

8.随机存取文件流:RandomAccessFile类可以在文件的任何地方查找或写入数据,它同时实现了DataOutput和DataInput接口。其seek方法用来设置文件指针位置,getFilePointer方法用来返回文件指针当前位置。如打开一个可同时进行读写操作的文件:

       RandomAccessFile inOut=new RandomAccessFile(“employee.dat”,”rw”);

9.文本输出:要想以二进制格式写入数据,使用DataOutputstream;要想以文本格式写入则使用PrintWriter;但是这两个类尽管提供了有用的输出方法,却没有定义目的地,因此PrintWriter必须同目标writer合并到一起,如:

       PrintWriter out=new PrintWriter(new FileWriter(“employee.txt”));

       也可以将其同目标流合并到一起,如:

       PrintWriter out=new PrintWriter(new FileOutputStream(“employee.txt”));

       PrintWriter(OutputStream)构造器会自动增加一个OutputStreamWriter以便将Unicode字符转换成流内的字节。为了向PrintWriter进行写操作,应使用print方法或者println方法。

10.读取文本:在Java中唯一用来处理文本输入的是BufferedReader,它包含一个ReadLine方法,可用来读取整行文本,需要将一个BufferedReader同一个输入源合并起来:

       BufferedReader in=new BufferedReader(new FileReader(“employee.txt”));

       一个典型的输入循环如下:

       String line;

       while((line=in.readline())!=null){

              …

       }

11.字符串分割器类StringTokenizer类是专门用来处理带分隔符的字符串的,在构造函数中指定欲处理的字符串及一个或多个分隔符;

12.如果想在对象流中保存和恢复任何一个类,则该类必须实现Serializable接口。Serializable接口没有方法。对象序列化机制使得可以如同存储文本或者数据字段一样简单地存储对象。

13.保存对象数据需要使用ObjectOutputStream,如:

       ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(“employee.dat”));

       Employee harry=…;

       Manager boss=…;

       out.writeObject(harry);

       out.writeObject(boss);

14.读回对象需要使用ObjectInputStream对象,如:

       ObjectInputStream in=new ObjectInputStream(new FileInputStream(“employee.dat”));

       Employee e1=(Employee)in.readObject();

       Employee e2=(Employee)in.readObject();

       读回对象时必须对已保存对象的数量,它们的顺序以及它们的类型做到心中有数。

15.因为当一个对象被重新装载后,它可能占据一个和原来那个截然不同的内存地址,所以对于对象内部的对象引用,不能保存和恢复它们的内存地址。为此,Java采用“序列化”方式,具体算法为:

       1)保存到磁盘的所有对象都获得一个序列号;

       2)当要保存一个对象时,先检查该对象是否已经被保存;

       3)如果以前保存过,只需写入“与已保存的具有序列号x的对象相同”标记;否则,保存它的所有数据;

       当要读回对象时,将上述过程简单地逆转即可。对于载入的每个对象,都要注意它的序列号,并记住它在内存中的位置。如果遇到与已经保存的具有序列号x的对象相同标记,就根据序列号来获取该对象的位置,并设置对象引用,令其指向那个内存地址。

       当使用对象流时,这些过程都会自动完成,对象流会分配序列号,并跟踪重复的对象。

16.有些数据字段是不应该被序列化的,这可以通过将其标志为transient来取消对该字段的序列化。

17.File类用来实现文件管理功能,它关心的是文件在磁盘上的存储,而流关心的是文件的内容。

原创粉丝点击