IO基础之对象流、打印流、标准的IO和扫描器类的简单说明

对象流:(序列化和反序列化)
序列化:
指把堆内存中的Java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他的网络节点(在网络上传输)我们把这个过程称之为序列化。
反序列化:把磁盘文件中的对象数据或者把网络节点的对象数据,恢复成Java对象的过程。


为什么需要序列化:
1、在分布式系统中,需要共享数据的JavaBean对象,都得做序列化,此时下需要把对象在网络上传输,此时就得把对象数据转换为二进制形式。
以后存储在HttpSession中的对象,都应该实现序列化接口(只有实现序列化接口的类,才能做序列化操作)。
2、服务钝化:如果服务发现某些对象好久都没有活动了,此时服务器就会把这些内存中的对象,持久化在本地磁盘文件中(Java对象-->二进制文件)。
如果某些对象需要活动的时候,先在内存中去寻找,找到就使用。找不到再去磁盘文件中,反序列化我们的对象数据,恢复成Java对象。


需要做序列化的对象的类,必须实现序列化接口:java.io.Serializable接口(标志接口[没有抽象方法])
底层会做判断,如果当前对象是Serializable的实例,才允许做序列化:boolean ret = java对象 instanceof Serializable;


在Java中大多数类都已经实现Serializable接口。

使用对象流来完成序列化和反序列化操作:
ObjectOutputStream:通过writeObject方法做序列化操作的;
ObjectInputStream:通过readObject方法做反序列化操作的。


准备一个Person类:

import java.io.Serializable;

/**
 * Created by Layne_Yao on 2017-7-29 下午4:49:43.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class Person implements Serializable {
	private static final long serialVersionUID = 1L;
	private String name;
	private String sex;
	private transient String password;//无需序列化
	private int age;

	public Person(String name, String sex, String password, int age) {
		this.name = name;
		this.sex = sex;
		this.password = password;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", sex=" + sex + ", password="
				+ password + ", age=" + age + "]";
	}
}

对象流序列化操作:

/**
 * Created by Layne_Yao on 2017-7-29 下午4:49:25.
 * CSDN:http://blog.csdn.net/Jsagacity
 */
public class ObjectStreamDemo {

	public static void main(String[] args) throws Exception {
		File file = new File("obj.txt");
		writeObject(file);
		readObject(file);
	}

	// 序列化操作
	private static void writeObject(File file) throws Exception {
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
				file));
		out.writeObject(new Person("Layne", "man","123456", 20));
		out.close();
	}

	//反序列化操作
	private static void readObject(File file) throws Exception {
		ObjectInputStream in = new ObjectInputStream(new FileInputStream(
				file));
		Person person = (Person) in.readObject();
		System.out.println(person);
		in.close();
	}
}

运行结果:



做反序列化操作必须存在对象的字节码对象。

序列化的细节,序列化的版本:
1、如果某些数据不需要做序列化,比如密码,该怎么做?

   理论上说,静态的字段和瞬态的字段是不能做序列化操作的。
   解决方案:给该字段加上一个修饰符:transient


2、序列化的版本问题:
  反序列化Java对象时必须提供该对象的class文件,现在问题是,随着项目的升级,系统的class文件也会升级(增加一个字段,或删除一个字段),
   这是如何保证两个class文件的兼容性?
   Java通过serialVersionUID(序列化版本号)来判断字节码是否发生改变。如果不显示定义serialVersionUID类变量,该类变量的值由JVM根据类相关信息计算,而修改后的类计算方式和之前往往不同。
   解决方案:在类中提供一个固定的serialVersionUID。

           private static final long serialVersionUID = 1L;




打印流:打印数据的,打印流只能是输出流
PrintStream:
字节打印流
PrintWriter:字符打印流
对于PrintWriter来说,当启用字段刷新之后,
PrintWriter pw = new PrintWriter(new FileOututStream(new File("file/out")),true);
调用println、或者printf、或者format方法,便会立马刷新操作
如果没有开启自动刷新,则需要手动刷新或者当缓冲区满的时候,再自动刷新
使用打印流作为输出流,此时的输出操作会特别简单因为在打印流中:
提供了print方法:打印不换行
提供了println方法:打印再换行
print和println方法可以支持打印输出各种数据类型的数据,记住void println(Object x)即可。


字节打印流:

public class PrintStreamDemo {
	public static void main(String[] args) throws Exception {
		PrintStream ps = new PrintStream(new File("file/out.txt"));
		ps.write("ABC".getBytes());
		ps.print(false);
		ps.print(18);
		ps.print("layne");
		
		//其实可以不用刷新
		ps.close();

	}

}

字符打印流:

public class PrintWriterDemo {
	public static void main(String[] args) throws Exception {
		PrintWriter ps = new PrintWriter(new File("file/out.txt"));
		ps.write("ABC");
		ps.print(false);
		ps.println(18);
		ps.print("layne");
		
		//其实可以不用刷新
		ps.close();
	}
}


打印流中的格式化输出(printf方法):

System.out.println();其实等价于PrintStream ps = System.out; ps.println();

//Java的格式化输出
public class printfDemo {
	public static void main(String[] args) {
		//打印一句话,效果:姓名:layne,年龄:18
		String name = "layne";
		int age = 18;
		//传统的打印风格
		String str = "姓名:"+name+",年龄:"+age;
		System.out.println(str);
		
		
		//格式化输出
		String format = "姓名:%s,年龄:%d";
		Object[] data = {name,age}; 
		System.out.printf(format,data);
		System.out.println();
		//简化
		System.out.printf("姓名:%s,年龄:%d",name,age);

	}

}

运行结果:




标准的IO:

标准的输入:通过键盘录入数据给程序
标准的输出:在屏幕上显示程序的数据


在System类中有两个常量:
InputStream in = System.in;
PrintStream out = System.out;


标准流的重定向操作:
标准的输入:通过键盘录入数据给程序;
重新指定输入的源不再是键盘,而是一个文件。
static void setIn(InputStream in);重新分配“标准”输入流。
此后,System.in数据的来源就是通过setIn指定的源。
标准的输出:在屏幕上显示程序的数据
重新指定输出的目标不再是屏幕,而是一个文件。
static void setOut(PrintStream out);重新分配“标准”输出流。

public class SystemIODemo {
	public static void main(String[] args) throws Exception {
		// 重定向标准输入流
		System.setIn(new FileInputStream("file/123_copy.txt"));
		//重定向标准输出流
		System.setOut(new PrintStream("file/print.txt"));
		
		System.out.println("...开始...");
		int data = System.in.read(); //读取文件123_copy.txt中的第一个字节
		System.out.println(data); 
		System.out.println("...结束...");
	}

}




Scanner:扫描类,在java.util包中,表示输入的操作
存在的方法:xxx表示数据类型,如byte,int,boolean等;
boolean hasNextXxx();//判断是否有下一种类型的数据
Xxx nextXxx();//获取下一个该类型的数据。

public class ScannerDemo {
	public static void main(String[] args) throws Exception {
		//扫描文件中的数据
		//Scanner sc = new Scanner(new File("file/ch.txt"),"GBK");
		//扫描键盘输入的数据
		//Scanner sc = new Scanner(System.in);
		//扫描字符串的数据
		Scanner sc = new Scanner("这是扫描类,我是即将被扫描的数据!!!");
		while(sc.hasNextLine()){
			String line = sc.nextLine();
			System.out.println(line);
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值