天天看点

Thinking in java 琐碎知识点之 I/O流 、对象序列化

Java I/O流 、对象序列化

1、File类

   此类的实例可能表示(也可能不表示)实际文件系统对象,如文件或目录。

   File类可以新建、删除和重命名文件和目录,但是File不能访问文件本身的内容,这要使用IO流。

   File对象的createNewFile()方法在磁盘上创建真实的文件

2. io流分类

  读取一个文件,输入流  

  写出一个文件,输出流

  字符流:专门用于读写文本文件的(记事本可以正常打开),字符流操作的最小数据单元是16位的字符 查询本机上的编码表(GBK)

  问题?word excel是不是文本文件

  常见的文本文件: .txt  .java  html  xml  sql

  字节流:操作的最小单元是8位的字节,最小的存储单位1个字节

          1个字节8个二进制位

 任意文件

   问题?能操作文件夹吗 (不能)

3、Java中的io继承体系

   继承体系,类与类之间继承关系,子类中的共性提取成的父类

   父类中定义的功能,是这个体系中的最共性的内容

   学习一个继承体系的时候,找父类去看,建立子类对象

   字符流:

     输出流,写入文件的抽象基类(体系中的最高层的父类) Writer

     输入流,读取文件的抽象基类 Reader

   字节流:

     输出流,写入文件的抽象基类 OutputStream

     输入流,读取文件的抽象基类 InputStream

4. 字符流的输入流(读文件)使用

   字符流读取文件

     查阅API文档找到了Reader

       read()方法读取单个字符,返回int值?

       返回的int值,是读取到的字符的ASCII码值

       read()方法,每执行一次,自动的向后读取一个字符

       读取到文件末尾的时候,得到-1的值

     找到Reader类的子类 FileReader

      FileReader(String fileName) 传递字符串文件名

      read(字符数组)

      返回int值

      数组中存储的就是文件中的字符

      int返回值,读到末尾就是-1

      int返回数组中,读取到的字符的有效个数

      好处:可以提高读取的效率

      注意问题:

        出现异常:XXXX拒绝访问

 A.操作,确认是不是操作的文件

 B.登录windows的账户是不是管理员,不是管理员登录的,不能操作c盘下的文件

    其他盘符是可以的

5.字符流的输出流(写文件)使用

    字符流写文件

    查阅API文档,找到了使用的子类,FileWriter

FileWriter(String fileName) 

          根据给定的文件名构造一个 FileWriter 对象。

void write(String str) 是FileWriter类的父类的方法

   记住:Java中字符流写数据,不会直接写到目的文件中,写到内存中

         想将数据写到目的文件中,刷新,刷到目的文本中

flush()刷新

   记住:流对象中的功能,调用了Windows系统中的功能来完成

         释放掉操作系统中的资源,简称:关闭流

close方法,关闭流之前,关闭的时候,先要刷新流中的数据

但是,如果写文件的数据量很大,写一句刷一句才好

    看到了父类中的write方法

    记住:IO操作,需要关闭资源,关闭资源的时候,开了几个流,就要关闭几个流

    单独的进行关闭资源,单独写try catch,保证每一个流都会被关闭

6. 复制文本文件

读取源文件 FileRreader

写入到目的文件 FileWriter

   两种文件复制方式,分别计算时间

读一个字符,写一个字符

第一个数组,写一个数组

   利用缓冲区复制文件

        第一行,写一行的操作

7. 字符流的缓冲区对象(也叫处理流、包装流)

   利用数组提升了文件的读写速度,运行效率提升了

   我们想到了效率问题,Java工程师(Oracle),也想到了提升效率

   写好了字符流的缓冲区对象,目的提供流的写,读的效率

   写入流的缓冲区对象BufferedWriter

BufferedWriter(Writer out)

参数Writer类型的参数,传递的参数是Writer类的子类对象

缓冲区,提供流的写的效率,哪个流的效率 FileWriter

         void newLine() 写一个换行,具有跨平台

不用newLine()方法,也可以实现换行 \r\n

\r\n Windows下的换行符号

\n Linux下的换行符号

   读取流的缓冲区对象BufferedReader

      BufferedReader(Reader in) 

      参数Reader类型参数,传递的是Reader类的子类对象

      缓冲区,提供流的读的效率,哪个流的效率FileRreader

      读取一行的方法 readLine(),文件末尾返回null

      不是末尾返回字符串 String 

8、字节流

9. 处理流PrintStream流的用法

10、重定向标准输入输出流

   Java的标准输入输出分别通过System.in和System.out来代表,默认情况下它们分别代表键盘和显示器

   System类提供了重定向标准输入输出的方法

Scanner和IO流接(BufferedReader)受键盘输入的比较(BufferedReader输入都被当成String对象,BufferedReader不能读取基本类型输入项)

11、RandomAccessFile对象

12、对象序列化

在Java中如果需要将某个对象保存到磁盘或者通过网络传输,那么这个类应该实现Serializable标记接口或者Externalizable接口之一

序列化的步骤:

a、创建一个ObjectOutputstream处理流(必须建立在其它结点的基础上)对象

b、调用ObjectOutputstream对象的writeObject方法输出可序列化对象

从二进制流中恢复Java对象的反序列化步骤(按照实际写入的顺序读取):

a、创建一个ObjectInputStream处理流(必须建立在其它结点的基础上)对象

b、调用ObjectInputstream对象的readObject方法输出可序列化对象(该方法返回的是Object类型的Java对象)

(反序列化恢复Java对象时必须要提供java对象所属类的class文件)

注:如果一个可序列化对象有多个父类,则该父类要么是可序列化的,要么有无参的构造器,因为反序列化机制要恢复其关联的父类实例

而恢复这些父类实例有两种方式:使用序列化机制、使用父类无参的构造器

采用Java序列化机制时,只有当第一次调用writeObject输出某个对象时才会将该对象转换成字节序列写到ObjectOutputStream

在后面程序中如果该对象的属性发生了改变,即再次调用writeObject方法输出该对象时,改变后的属性不会被输出

如果父类没有实现Serializable接口,则其必须有默认的构造函数(即没有参数的构造函数)

但是若把父类标记为可以串行化,则在反串行化的时候,其默认构造函数不会被调用。

这是因为Java 对串行化的对象进行反串行化的时候,直接从流里获取其对象数据来生成一个对象实例,而不是通过其构造函数来完成。

13、自定义序列化

 在属性前面加上transient关键字,可以指定Java序列化时无需理会该属性值,由于transient修饰的属性将被完全隔离在序列化机制外,

 这会导致在反序列化恢复Java对象时无法取得该属性值。

 实现自定义序列化要重写类的如下方法:

 private void writeObject(java.io.ObjectOutputStream out) throws IOException;

 private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException;

 还有种更彻底的序列化机制可以在序列化某对象时替换该对象,此种情况下应为序列化类提供如下特殊方法:

 ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

 Java的序列化机制保证在序列化某个对象之前,先调用对象的writeReplace()方法,如果该方法返回另一个Java对象,

 则系统转为序列化另一个对象。

 小结:系统在序列化某个对象之前,先会调用该对象的如下两个方法:

 writeReplace和writeObject,系统先调用被序列化对象的writeReplace方法,如果返回另一个Java对象,则再次调用该java对象的writeReplace方法....

 直到该方法不在返回一个对象为止,程序最后调用该对象的writeObject方法来保存该对象的状态

 与writeReplace方法相对的有一个方法可以替代原来反序列化的对象

 即:private Object readResolve() throws ObjectStreamException;

 这个方法会紧接着readObject之后被立即调用,该方法的返回值会代替原来反序列化的对象,而原来readObject反序列化的对象会被立即丢弃

 (此方法在序列化单例类、早期枚举类时很有用)

14、另一种序列化机制:Java类实现Externalizable接口

    两种序列化机制的区别:

      实现Serializable接口      

      系统自动存储必要信息   

      Java内建支持,易于实现只需实现该接口即可            

      无须任何代码支持    

      性能略差  

  实现Externalizable接口 

  程序员决定需要存储哪些信息

 仅仅提供两个空方法实现该接口必须为两个空方法提供实现

 类中必须存在一个无参构造方法

 性能略高

Java新I/O 

15、Charset对象

    Java提供了Charset来处理字节序列和字符序列之间的转换关系,该类包含了用于创建解码器和编码器的方法

    例程:CharsetTransformTest.java

16、Buffer(缓冲)抽象基类

    常用子类ByteBuffer,这些Buffer的子类不是通过构造器创建而是通过static xxxBuffer allocate(int capacity)来创建一个容量为capacity的xxxBuffer对象。Buffer中包含两个重要的方法flip(该方法将limit设置为position所在位置,position设置       为0,)和clear(将position设为0,limit设为 capacity)。flip为从Buffer中读取数据做好准备,而clear是为向Buffer中装入数据做好准备

例程:BufferTest.java

17、Channel(通道)

    程序不能直接访问Channel中放入数据,Channel只能和Buffer进行交互,发送到Channel中的数据必须先放到Buffer对象中,程序再将Buffer的输入写入Channel。而从Channel中读取数据也必须先读到Buffer中,程序再从Buffer中取出这些数据。

例程:FileChannelTest.java