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

来源:互联网 发布:mac玩lol 编辑:程序博客网 时间:2024/06/10 23:05
对象流:(序列化和反序列化)
序列化:
指把堆内存中的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;}@Overridepublic 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,年龄:18String 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);}}}

原创粉丝点击