java-day18

缓冲流

缓冲流:文件输入流与文件输出流的加强板,它的的读写速度比文件输入流或文件输出流更快。

  • 字节缓冲流BufferedInputStreamBufferedOutputStream

  • 字符缓冲流BufferedReaderBufferedWriter

创建缓冲流的对象时一般调用当前类的带一个参数(对应的字节(或字符)输入(或输出)流对象)的构造器,之后的写入或读出数据的步骤与对应的输入输出流的写法大致相同,由于字符缓冲流运用public void newLine():方法读写文本文件时存在缺陷(即:当第一行文本还没有读写完毕就做了换行操作,从而是读取的第一行文本的数据不完整),所以还是用原本的字符输出流中的read方法读写文本文件。

转换流

编码与解码:

按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。

编码:字符(能看懂的)--字节(看不懂的)

解码:字节(看不懂的)-->字符(能看懂的)

字符编码Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。

我们通常使用的字符集 Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。可见,当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的。

当一个文件到的编码格式与操作系统的默认编码格式不一致时,读取该文件的时候会出现乱码的情况,写入数据是会卡bug,所以就要用转换流来解决这些问题。

转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法

  • InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。

  • InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。

构造举例,代码如下:

InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");

转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法

  • OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。

  • OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。

构造举例,代码如下:

OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("out.txt"));
OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("out.txt") , "GBK");

序列化与反序列化

一、序列化。运用java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

序列化操作

  1. 一个对象要想序列化,必须满足两个条件:

  • 该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException

  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。

2.写出对象方法

  • public final void writeObject (Object obj) : 将指定的对象写出。

注意:进行序列化操作之前必须先用public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream。构造举例,代码如下:

FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);

二、反促裂化。运用ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

步骤:首先运用public ObjectInputStream(InputStream in): 创建一个指定InputStream的ObjectInputStream。再进行反序列化操作

如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream读取对象的方法:

用public final Object readObject () : 读取一个对象。代码如下:

public class DeserializeDemo {
   public static void main(String [] args)   {
        Employee e = null;
        try {        
             // 创建反序列化流
             FileInputStream fileIn = new FileInputStream("employee.txt");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             // 读取一个对象
             e = (Employee) in.readObject();
             // 释放资源
             in.close();
             fileIn.close();
        }catch(IOException i) {
             // 捕获其他异常
             i.printStackTrace();
             return;
        }catch(ClassNotFoundException c)  {
            // 捕获类找不到异常
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
        }
        // 无异常,直接打印输出
        System.out.println("Name: " + e.name);    // zhangsan
        System.out.println("Address: " + e.address); // beiqinglu
        System.out.println("age: " + e.age); // 0
    }
}

当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。发生这个异常的原因如下:

  • 该类的序列版本号与从流中读取的类描述符的版本号不匹配

  • 该类包含未知数据类型

  • 该类没有可访问的无参数构造方法

Serializable 接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

序列化集合

  1. 将存有多个自定义对象的集合序列化操作,保存到list.txt文件中。

  2. 反序列化list.txt ,并遍历集合,打印对象信息。

步骤:

  1. 把若干对象 ,保存到集合中。

  2. 把集合序列化。

  3. 反序列化读取时,只需要读取一次,转换为集合类型。

  4. 遍历集合,可以打印所有的对象信息

猜你喜欢

转载自blog.csdn.net/weixin_41804367/article/details/89011630