.pwd;
上面我们演示的文件的操作,如果换成字节数组流也是一样的方式。最后总结下:
1. 如果对象需要被写出到文件上,那么对象所属的类必须要实现Serializable接口。 Serializable接口没有任何的方法,是一个标识接口而已。
2. 对象的反序列化创建对象的时候并不会调用到构造方法的、(这点文中没有说到,想要验证的同学在构造方法后面加一句System.out.println("构造方法执行吗?");,实际上构造方法是不执行的,自然这句话也没有输出了)
3. serialVersionUID 是用于记录class文件的版本信息的,serialVersionUID这个数字是通过一个类的类名、成员、包名、工程名算出的一个数字。
4. 使用ObjectInputStream反序列化的时候,ObjeectInputStream会先读取文件中的serialVersionUID,然后与本地的class文件的serialVersionUID
进行对比,如果这两个id不一致,反序列则失败。
5. 如果序列化与反序列化的时候可能会修改类的成员,那么最好一开始就给这个类指定一个serialVersionUID,如果一类已经指定的serialVersionUID,然后
在序列化与反序列化的时候,jvm都不会再自己算这个 class的serialVersionUID了。
6. 如果一个对象某个数据不想被序列化到硬盘上,可以使用关键字transient修饰。
7. 如果一个类维护了另外一个类的引用,则另外一个类也需要实现Serializable接口。
四、打印流【处理流】
PrintStream 用于向文本输出流打印对象的格式化表示形式。它实现在PrintStream 中的所有 print 方法。它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。
在理解PrintStream如何使用之前,先了解一下System类中三个字段:
往控制台输出时 ,使用System.out.println();
其中System.out这个字段返回的就是打印流,PrintStream
PrintStream ps=System.out; ps.print("hello"); 就等同于 System.out.println("hello");
err和out其实是一样的,只不过在控制台输出时,err输出内容是红色的
Scanner也是一个处理流,创建一个Scanner对象使用到的就是in字段
Scanner console=new Scanner(System.in);
Scanner类其实就是一个输入流,那么我们可以从控制台输入,怎样从文件中输入呢?
InputStream is=System.in;
File file=new File("F:/Picture/test/test2.txt");
is=new BufferedInputStream(new FileInputStream(file));
Scanner sc=new Scanner(is);
System.out.println(sc.nextLine());
从上面也可以看出Scanner 其实就一个处理流,用于增强节点流。
使用打印流输出内容到文件中,也是很容易的
这是PrintStream的构造方法
File file=new File("F:/Picture/test/test.txt");
PrintStream ps=new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
ps.append("hellohahaha");
ps.close();
最后总结一句话:对于标准的输入和输出,JDK 中封装好了比较好的操作类,输入的Scanner 输出PrintStream
最后一个小问题:如何将system.out 的输出不是输出到控制台,而是记录到文件中呢?即记录日志利用打印流来实现的。
文本信息中的内容为String类型。而像文件中写入数据,我们经常用到的还有文件输出流对象FileOutputStream.
1 File file = new File("F:\\a.txt");
2 FileOutputStream outputStream = new FileOutputStream(file,true);//第二个参数为追加文本
3 outputStream.write(97);
上面的代码执行完之后,a.txt中的内容存的是a,因为write方法接收的为byte类型的数据,97对应的ASCII码为a。
假设我就想将97写入到文件中呢?那么得将第三行代码改为
outputStream.write("97".getBytes());//先将97作为字符串再转换为byte数组
而PrintStream得出现,是的我们写数据入文件变得十分方便,你传入的是什么,就会给你写入什么数据。原因是他内部帮我们转换了
File file = new File("F:\\a.txt");
PrintStream printStream = new PrintStream(file);
printStream.println(97);
printStream.println('a');
printStream.println("hello world");
printStream.println(true);
printStream.println(3.14);
printStream.println(new Student("酒香逢"));
上面这段代码得到的结果为:
可见不管什么数据类型,都会转换为字符串,甚至是对象也不例外。
这里再说一下学习java时少不了用到的一句代码:System.out.println();代码中的out,为System类中的一个PrintStream对象,称之为标准输出流对象。标准输出流对象会将数据打印到控制台上。查阅API可知有如下方法,
static void setOut(PrintStream out) //重新分配“标准”输出流。
可以重新指定输出流对象,即将System.out.println();的输出内容打印到我们想打印到的地方。
1 File file = new File("F:\\a.txt");
2 PrintStream printStream = new PrintStream(file);
3 System.setOut(printStream);
4 System.out.println("打印到F:\\a.txt中");
这时候内容回写入到文件a.txt中去,而不是打印在控制台中。
最后回归本文重点,日志信息的保存。
假设有代码:
1 try{
2 int n = 5/0;
3 }catch(Exception e){
4 e.printStackTrace();
执行结果会抛出我们想要的错误日志信息。
java.lang.ArithmeticException: / by zero
at log.DemoLog.main(DemoLog.java:26)
这时候想将日志信息保存起来怎么办呢?
看到Exception类中的这3个重载方法,我们不难得知,只要给他指定一个打印输出流对象当中,即可将日志信息保存到我们想要的地方。
File file = new File("F:\\a.log");
PrintStream printStream = new PrintStream(file);
try{
int n = 5/0;//除数为零异常
}catch(Exception e){
e.printStackTrace(printStream);
上面这段代码执行重复执行多次,
但是记录的日志信息永远只会记录一条。这明显不是我们想得到的,日志信息,总不能只记录一条吧?那么它存在又有什么用?
其实,追加文本信息的决定者不是e.printStackTrace(printStream);方法,关键点在于流对象,
可见打印流对象是存在一个OutputStream接口作为参数的传入对象。既然是接口,那么就无法new出OutputStream的对象了,可以用他的子类FileOutputStream对象作为参数传入。并且,FileOutputStream流是可以追加的,
new FileOutputStream(file,true);//第二个参数为追加文本
此时将其作为参数传入,PrintStream流自然也就可以追加内容了。
File file = new File("F:\\a.log");
PrintStream printStream = new PrintStream(new FileOutputStream(file,true),true);
try{
int n = 5/0;//除数为零异常
}catch(Exception e){
e.printStackTrace(printStream);
将代码执行3次后:
可以看到日志信息是保存有3条的,日志信息记录保存目的达成!
最后如果我们如果想回来呢?
改为控制台输出需要借助FileDescript这个类,之后的输出就会显示在控制台了
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out),true));
备注:部分资料来源于网络,表示感谢.