您的位置:首页 > 其它

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

2017-08-01 19:14 453 查看
对象流:(序列化和反序列化)

序列化:
指把堆内存中的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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐