java IO 字节流、字符流操作总结三之字符流、序列化和反序列化

来源:互联网 发布:网络视频下载软件 编辑:程序博客网 时间:2024/06/05 21:18

这一篇我讲介绍一下字符流。什么是字符流,就是若干个字节组成一个字符。(为什么说是若干个,不能确定吗)这里就来说说原因和编码问题。

首先说说字符编码的问题,比较常用的编码有gbk,utf-8等。

a、.编码问题(看前面所描述的)。

1、gbk 编码中文占用2个字节,英文占用1个字节。

2、utf-8编码中文占用3个字节,英文占用1个字节。

b、认识文本与文本文件

Java是双字节编码,utf-16be编码。即char占用2个字节。注意:当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式。否则会出现乱码。文本文件就是字节序列,可以是任意编码的字节序列。但是通常我们在中文的机器上直接创建文件,那么该文件只认识ANSI编码。

文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储。

c、字符流分为输入流(writer)和输出流(reader)。操作的是文本、文本文件字符的处理,一次处理一个字符。但是我们要知道字符的底层还是基本的字节序列(字节传输才是文件最终的传输)。

这里我们来上一张字符流的家族谱。


字符流的基本实现:

InputStreamReader:完成byte流解析为char流,按照编码解析

InputStreamWriter:完成char流到byte流的解析,按照编码处理

 

d、FileReader&FileWriter(文件的输入输出字符流)

可以直接写文件名的路径。与InputStreamReader相比坏处:无法指定读取和写出的编码,容易出现乱码。

FileReader fr=new FileReader(“Demo\\im.txt”);//输出流FileWriter fw=new FileWriter(“Demo\\im2.txt”);输入流

e、字节流的过滤器

BufferedReader:readLine();一次读取一行,但不能识别换行。。

BufferedWriter/PrintWriter;一次写一行,PrintWriter可以自动换行

如:一次写入一行

BufferedWriter                                      PrintWriter

bw.wrire(line)                                       pw.println(line);//自动换行,不加ln不换行

bw.newLine();//单独换行                    pw.flush();//刷新数据

bw.flush();//刷新数据

代码如下:

package com.ll.iofile;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.PrintWriter;/** * 这个例子是用来测试字节流的过滤器 * BufferedReader和BufferedWriter/PrintWriter类的使用 * @author LULEI * */public class testBufferedReaderAndBufferedWriter {public static void main(String[] args) throws IOException{// TODO Auto-generated method stub//实例化一个BufferedReader的对象BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("C:\\Users\\Administrator\\Desktop\\搜狗.txt")));//实例化一个BufferedWriter的对象BufferedWriter wr=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("Demo\\immoc1.txt")));//实例化一个PrintWriter的对象PrintWriter pw=new PrintWriter(new OutputStreamWriter(new FileOutputStream("Demo\\imooc2.txt")));String line=new String();while((line=br.readLine())!=null){/*测试BufferedWriter的write方法wr.write(line);//这样直接输入的只会在一行显示wr.newLine();//这句话起到读取一行就换行的作用wr.flush();*///System.out.println(line);//每读取一行字节,直接输出//测试PrintWriter的方法pw.println(line);//输出一行字节的内容,且加ln自动换行pw.flush();}wr.close();br.close();pw.close();}}


这里我就先介绍几个比较常用的字符流。接下来介绍一下序列化和反序列化的知识。

f、什么是对象的序列化与反序列化?

1、对象的序列化是指将object对象转换成byte序列,反之将byte序列转换为object对象称之为反序列化。

2、序列化流(objetcOutputStream),是过滤流。方法:writeObject()

      反序列化流(objectInputStream),方法:readObject()的使用需要进行强制类型的转换。

3、序列化接口(serializable)

对象必须实现序列化接口才能进行序列化,否则将会出现异常。这个接口没有任何的方法,只是一个标准。

代码如下:

package com.ll.iofile;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;/** * 这个类是用于测试对象的序列化和反序列化 * 调用ObjectOutputSrteam 和ObjectInputStream类的使用 * @author LULEI * */public class testObjectSerializableDemo {public static void main(String[] args) throws Exception{// TODO Auto-generated method stub//1、实现对象的序列化流的对象String file="Demo/object.txt";ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));//实例化一个MobilePhone对象MobilePhone mp=new MobilePhone(4, 5.5f, "红米Note");//开始写对象oos.writeObject(mp);//刷新缓冲区数据oos.flush();oos.close();//2实现对象的反序列化流对象ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));//必须进行强制类型转换MobilePhone mps=(MobilePhone)ois.readObject();System.out.println(mps);ois.close();}}package com.ll.iofile;import java.io.Serializable;/** * 这个类是用于参与测试对象的序列化和反序列化 * ObjectOutputSrteam 和ObjectInputStream类的使用 * @author LULEI * *///这里必须要继承serializable接口public class MobilePhone implements Serializable {private int cpu;private float screen;private String name;public MobilePhone(){}public MobilePhone(int cpu, float screen, String name) {super();this.cpu = cpu;this.screen = screen;this.name = name;}public int getCpu() {return cpu;}public void setCpu(int cpu) {this.cpu = cpu;}public float getScreen() {return screen;}public void setScreen(float screen) {this.screen = screen;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "MobilePhone [cpu=" + cpu + ", screen=" + screen + ", name="+ name + "]";}}

g、 transient关键字

transient关键字修饰的属性默认是不能序列化的,但是可以使用writeObject()自己完成这个元素的序列化。ArrayList就是用了此方法进行了优化的操作。ArrayList最核心的容器Object[] elementData使用了transient修饰,但是在writeObject自己实现对elementData数组的序列化。只能序列化数组中真实存在的元素,对于数组中的空的元素时不能进行序列化的。

如:

private void writeObject(java.io.ObjectOutputStream s) throwsjava.io.IOException{ }private void readObject(java.io.ObjectOutputStream s) throwsjava.io.IOException,classNotFoundException{ } 

代码如下:

package com.ll.iofile;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;/** * 这个类是用于测试对象的序列化和反序列化 * 调用ObjectOutputSrteam 和ObjectInputStream类的使用 * 1、首先实例化ObjectOutputSrteam 和ObjectInputStream类的对象oos和ois * 2、实例化将要序列化的对象qq * 3、对象oos调用writeObject()方法来对对象qq进行序列化流的输出操作。 * 4、对象ois调用readObject()方法来进行反序列化的输入操作。同时要使用强制类型转换来转化 * 赋值给相应的实例化对象x。 * 4、最后直接输出x的内容 * @author LULEI * */public class testTransient {public static void main(String[] args) throws IOException{// TODO Auto-generated method stub//1、实例化首先实例化ObjectOutputSrteam 和ObjectInputStream类的对象String file=new String("Demo\\testTransient");ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));//2、实例化将要被序列化的对象MobilePhoneMobilePhone2 mp=new MobilePhone2(4, 4.0f, "华为");//3、oos对象调用writeObject()方法来进行序列化oos.writeObject(mp);oos.flush();//刷新缓冲区oos.close();//关闭文件流//4、ois对象调用readObject方法来进行反序列化的操作,同时赋值给相应类型的对象try {MobilePhone2 mps=(MobilePhone2)ois.readObject();System.out.println(mps);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}ois.close();}}package com.ll.iofile;import java.io.Serializable;/** * 这个类是用于参与测试对象的序列化和反序列化 * ObjectOutputSrteam 和ObjectInputStream类的使用 * 同时检测了transient关键字的使用 * @author LULEI * *///这里必须要继承serializable接口public class MobilePhone2 implements Serializable {private int cpu;//使用transient关键字修饰,这时screen的值不会被序列化。这时//如果想进行序列化,只能够自己人为的进行序列化private transient float screen;private String name;public MobilePhone2(){ }public MobilePhone2(int cpu, float screen, String name) {super();this.cpu = cpu;this.screen = screen;this.name = name;}/*这里是自己认为的完成序列化的操作//人工的进行序列化private void writeObject(java.io.ObjectOutputStream s)        throws java.io.IOException{s.defaultWriteObject();//则是执行默认的序列化操作s.writeFloat(screen);//自己人工的进行screen序列化操作}//人工的进行反序列化的操作 private void readObject(java.io.ObjectInputStream s)        throws java.io.IOException, ClassNotFoundException { s.defaultReadObject();//执行默认的反序列化的操作 this.screen=s.readFloat();//自己完成screen的反序列化的操作 } */public int getCpu() {return cpu;}public void setCpu(int cpu) {this.cpu = cpu;}public float getScreen() {return screen;}public void setScreen(float screen) {this.screen = screen;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "MobilePhone [cpu=" + cpu + ", screen=" + screen + ", name="+ name + "]";}}

h、序列化过程中子父类构造函数的问题

1>父类实现了serializable接口,子类继承父类就可以序列化了。

2>但子类在进行反序列化的时候,父类 实现了序列化接口,则不会递归调用其构造函数。

3>父类未实现了serializable接口,子类自己实现了接口,子类可以自行实现可序列化。

4>子类在反序列化时,父类没有实现序列化的接口,则会递归调用其构造函数。

  
到这里,我的Java IO部分的基础知识算是学完了。这里做了总结,方便以后来复习。。。。

1 0