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

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

首先说说字符编码的问题,比较常用的编码有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;
	}
	@Override
	public 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) throws
java.io.IOException{
 }
private void readObject(java.io.ObjectOutputStream s) throws
java.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、实例化将要被序列化的对象MobilePhone
		MobilePhone2 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 block
			e.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;
	}
	@Override
	public String toString() {
		return "MobilePhone [cpu=" + cpu + ", screen=" + screen + ", name="
				+ name + "]";
	}
	
}

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

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

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

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

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

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值