目录
一、对象处理流
1.作用 :
既可以保存数据的值,也可以保存数据的数据类型;使得数据被保存到文件中后,还能够从文件中恢复。
eg1 : 一个基本类型数据 int i = 5; ,对象处理流可以将i变量的值5和它的数据类型int都保存到文件中;
eg2 : 一个引用类型数据 Cat cat = new Cat("bubble", 5, "white");,对象处理流可以将cat变量的值String-"bubble", int-5, String-"white"都保存下来,还可以记录下它的数据类型是Cat类型。
2.序列化和反序列化 :
序列化——保存数据的值和数据类型到文件中。
反序列化——将文件中保存的数据(包含值和数据类型)重新恢复成数据本身。
如下图所示 :
PS : 若想让某个类的对象支持序列化机制,必须让该类实现可序列化,即,实现以下两个接口之一 ——
1°Serializable,一个标记接口(标记接口指“没有定义方法,只做了声明”的接口),如下图所示:
2°Externalizable,一个继承了Serializable类的接口,并且在接口中定义了两个抽象方法,如下图所示 :
Δ一般情况下,推荐继承第一个接口Serializable(不需要实现抽象方法)。
3.ObjectOutputStream :
1° 概述
ObjectOutputStream继承自OutputStream类;它可以实现数据的序列化。ObjectOutputStream类同样使用了“修饰器模式”,即该类中有一个OutputStream的引用变量(存在于OutputStream类的静态内部类BlockDataOutputStream中),如下 :
通过ObjectOutputStream的带参构造,可以传入一个OutputStream类的子类对象,以实现多态,如下所示 :
实现多态后,可以通过动态绑定机制,调用传入类型的特有方法。
2° 演示
up以ObjectOutputStream_Demo类作为测试类,代码如下 :
packagecsdn.knowledge.api_tools.iocurrent.object_current; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.ObjectOutputStream; importjava.io.Serializable; publicclassObjectOutputStream_Demo { publicstaticvoidmain(String[] args) throwsIOException { /*序列化之后,保存的文件格式不是纯文本。*/ObjectOutputStreamobjectOutputStream=newObjectOutputStream(newFileOutputStream("D:\\JAVA\\IDEA\\fileEX\\d1.dat")); //写入字符串objectOutputStream.writeUTF("Cyan_RA9"); //自动装箱objectOutputStream.writeInt(141); objectOutputStream.writeDouble(233.33); objectOutputStream.writeChar('A'); //序列化对象objectOutputStream.writeObject(newCat("bubble", 5, "white")); //释放资源objectOutputStream.close(); } } //序列化对象的必须条件————实现Serializable接口 或 ExternalizableclassCatimplementsSerializable { privateStringname; privateintage; privateStringcolor; //建议添加该语句————//private static final long serialVersionUID = 1L;publicCat(Stringname, intage, Stringcolor) { this.name=name; this.age=age; this.color=color; } publicStringtoString() { return"Cat{"+"name='"+name+'\''+", age="+age+", color='"+color+'\''+'}'; } }
运行结果 :
非纯文本文件使用文本编辑器打开会出现乱码,但是依然可以看出一些端倪。
4.ObjectInputStream :
1° 概述
ObjectInputStream类也继承自OutputStream类;它可以实现数据的反序列化。ObjectInputStream类同样使用了“修饰器模式”,即该类中有一个InputStream的引用变量(存在于InputStream类中的静态内部类PeekInputStream中),如下 :
通过ObjectInputStream的带参构造,可以传入一个InputSream类的子类对象,以实现多态,如下所示 :
实现多态后,可以通过动态绑定机制,调用传入类型的特有方法。
2° 演示
up以ObjectInputStream_Demo类为演示类,代码如下 :
packagecsdn.knowledge.api_tools.iocurrent.object_current; importjava.io.FileInputStream; importjava.io.IOException; importjava.io.ObjectInputStream; publicclassObjectInputStream_Demo { publicstaticvoidmain(String[] args) throwsIOException, ClassNotFoundException { ObjectInputStreamobjectInputStream=newObjectInputStream(newFileInputStream("D:\\JAVA\\IDEA\\fileEX\\d1.dat")); /*1.反序列化的顺序必须和序列化时的顺序一致,即读取数据和保存数据的顺序一致,否则会出现类型转换异常。2.更改源数据后,要重写保存,才能读取到最新时间的数据。3.必须使读取数据的类能够访问到对象的类*/System.out.println(objectInputStream.readUTF()); System.out.println(objectInputStream.readInt()); System.out.println(objectInputStream.readDouble()); System.out.println(objectInputStream.readChar()); //抛出异常System.out.println(objectInputStream.readObject()); /*PS : 若想使用子类特有的方法,需要进行类型转换。*/ } }
运行结果 :
5.关于序列化的细节 :
1° 序列化或者反序列化的对象必须实现实现Serializable接口;并且序列化和反序列化时写入数据与读取数据的顺序必须一致。
2° 序列化类中,建议添加serialVersionUID,可以提高版本的兼容性。
3° 序列化对象时,默认要将里面所有属性都进行序列化,但不包括static和transient修饰的成员。
4° 序列化对象时,要求里面的属性的类型也要实现序列化接口。(eg : String, Integer等类已实现了序列化)
5°序列化具备可继承性,即如果某个类实现了序列化,默认其所有子类也实现了序列化。(eg : Number ---> Serializable)
6.标准输入输出流:
System.in——标准输入,System类中的一个公有静态引用常量,编译类型是InputStream类型,默认设备是键盘。如下图所示 :
System.out——标准输出,System类中的一个公有静态引用常量,编译类型是PrintStream类型,默认设备是显示器。如下图所示 :
两者的运行类型如下图所示 :
PS : Scanner sc = new Scanner(System.in); 中,"System.in"实际就是一个BufferedInputStream。
二、转换流
1.概述 :
若在txt文件中出现中文,并且该文件没有使用UTF-8形式编码;在使用IO流读取文件时就会出现乱码问题。
转换流可以解决乱码问题,转换流可以将字节流转成字符流,同时指定读取文件时按照怎样的编码方式。
常见转换流有两个 —— InputStreamReader和 OutputStreamWriter。
2.InputStreamReader :
InputStreamReader是Reader抽象类的一个子类,因此它本身属于字符流范畴。完成转换所调用的构造器如下,需要传入一个InputStream类的子类对象,以及一个编码类型。
以InputStreamReader_Demo类为演示类,代码如下 :
packagecsdn.knowledge.api_tools.iocurrent.transformation; importjava.io.*; importstaticjava.nio.charset.StandardCharsets.UTF_8; publicclassInputStreamReader_Demo { publicstaticvoidmain(String[] args) throwsIOException { InputStreamReaderinputStreamReader=newInputStreamReader(newFileInputStream("D:\\JAVA\\IDEA\\file\\3.txt"), UTF_8); BufferedReaderbufferedReader=newBufferedReader(inputStreamReader); Stringdata; while ((data=bufferedReader.readLine()) !=null) { System.out.println(data); } bufferedReader.close(); } }
运行结果 :
3.OutputStreamWriter :
OutputStreamWriter类继承自Writer类,转换方法与InputStreamWriter同理。
以OutputStreamWriter_Demo类为演示类,代码如下 :
packagecsdn.knowledge.api_tools.iocurrent.transformation; importjava.io.FileNotFoundException; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.OutputStreamWriter; /*** @author : Cyan_RA9* @version : 21.0*/publicclassOutputStreamWriter_Demo { publicstaticvoidmain(String[] args) throwsIOException { OutputStreamWriteroutputStreamWriter=newOutputStreamWriter(newFileOutputStream("D:\\JAVA\\IDEA\\fileEX\\1.txt"), "UTF-16"); outputStreamWriter.write("Space-X, 星舰发射!"); outputStreamWriter.close(); } }
运行效果 :
三、打印流
1.PrintStream :
PrintStream的类图如下 :
PS : PrintStream间接继承自OutputStream抽象类,属于字节流;
以PrintStream_Demo类为演示类,代码如下 :
packagecsdn.advanced.io.print; importjava.io.IOException; importjava.io.PrintStream; publicclassPrintStream_Demo { publicstaticvoidmain(String[] args) throwsIOException { //out本身是PrintStream类型PrintStreamprintStream=System.out; //默认输出设备是显示屏printStream.println("Space-X!"); printStream.write("YYDS".getBytes()); //更改输出设备到文件System.setOut(newPrintStream("D:\\JAVA\\IDEA\\fileEX\\4.txt")); System.out.println("这盛世,如您所愿!"); printStream.close(); } }
运行结果 :
2.PrintWriter :
PrintWriter的类图如下 :
PS : PrintWriter类直接继承自Writer抽象类,属于字符流。
以PrintWriter_Demo类为演示类,代码如下 :
packagecsdn.advanced.io.print; importjava.io.FileWriter; importjava.io.IOException; importjava.io.PrintWriter; publicclassPrintWriter_Demo { publicstaticvoidmain(String[] args) throwsIOException { //打印到控制台PrintWriterprintWriter1=newPrintWriter(System.out); //打印到文件(使用FileWriter的追加模式)PrintWriterprintWriter2=newPrintWriter(newFileWriter("D:\\JAVA\\IDEA\\fileEX\\4.txt", true)); printWriter1.println("嘤嘤嘤"); printWriter1.close(); printWriter2.println("嘤嘤嘤嘤嘤嘤"); printWriter2.close(); } }
运行结果 :
四、Properties类内容补充
1.拾枝杂谈 :
在“Hashtable源码分析及其子类Properties讲解”一文中,已有简略地介绍过Properties类。(如何导入数据,读取数据,追加数据)
Properties类是专门用于读取配置文件的集合类,也以键值对的形式保存数据;键值对默认为String类型。
2.常见方法 :
1°load——加载配置文件的键值对到当前Properties类对象
2°list——将数据显示到指定设备
3°getProperty(key)——根据键获取值
4°setProperty(key, value)——设置自定义键值对到Properties类对象
5°store——将Properties类对象中的键值对信息存储到配置文件;在IDEA中,如果键值对中包含中文,会将中文对应的unicode码存储到配置文件。
3.代码演示 :
以PropertiesEX类为演示类,代码如下 :
packagecsdn.advanced.io.standart; importjava.io.*; importjava.util.Iterator; importjava.util.Properties; /*** @author : Cyan_RA9* @version : 21.0*/publicclassPropertiesEX { publicstaticvoidmain(String[] args) throwsIOException { Propertiesproperties=newProperties(); Readerreader=newBufferedReader(newFileReader("D:\\JAVA\\IDEA\\file\\demo2.properties")); Writerwriter=newFileWriter("D:\\JAVA\\IDEA\\file\\demo3.properties", true); properties.load(reader); //listing propertiesproperties.list(System.out); //标准输出Iterator<String>iterator=properties.stringPropertyNames().iterator(); while (iterator.hasNext()) { Stringkey=iterator.next(); System.out.println("key = "+key+" whilst value = "+properties.getProperty(key)); } properties.setProperty("color", "cyan"); properties.store(writer, "try it"); reader.close(); writer.close(); } }
运行效果 :
System.out.println("END------------------------------------------------------------------------------");