标准输入流http://System.in
源数据源是标准输入设备(键盘、鼠标、触摸屏)等输入设备。在java中用http://System.in 得到一个InputStream字节输入流。
例如,在控台输入一句话,然后原样输出。
public static void main(String[] args) throws IOException {
// 需求:输入一句话,然原样输出
InputStream in = System.in;
byte[] buf = new byte[1024];
int len;
// buf中包含回车和换行
len = in.read(buf);
String str = new String(buf, 0, len);
// System.out.println(Arrays.toString(buf));
System.out.println(str);
}
System
类包含一些有用的类字段和方法。它不能被实例化。 里面提供的方法都是静态方法。
注意: 标准输入流以字节流流入内存,如果在控制台中输入字符,字符以默认编码(win简体:gbk)编码成字节进入标准输入流。win7系统的话默认编码为GBK。Linux系统则为UTF-8。
也可以用http://System.in来高效的读取一行数据。
InputStream in = System.in;
InputStreamReader reader = new InputStreamReader(in, "GBK");
BufferedReader br = new BufferedReader(reader);
标准输出流(PrintStream)
数据目的地是标准输出设备(显示器)等输出设备。在java中用System.out得到一个PrintStream 字节输出流(字节打印流)。提供了更强大的 print、println 打印方法用于打印各种数据类型。
比如读取某个文件的内容并打印出来,显示到标准的输出设备。
public static void main(String[] args) throws IOException {
File file = new File("d:javatestk.txt");
FileReader reader = new FileReader(file);
BufferedReader br = new BufferedReader(reader);
PrintStream ps = System.out;
String line;
while( (line=br.readLine())!=null ) {
ps.println(line);
}
}
注意:PrintStream打印的所有字符都用默认字符编码转换为字节。
public class Test03 {
public static void main(String[] args) throws IOException {
String str = "hello中国";
byte[] buf = str.getBytes("utf-8");
PrintStream ps = System.out;
ps.write(buf);
}
}
因为我用的是win10系统,所以默认的编码为GBK,程序中的buf使用的是UTF-8编码集,程序输出后得到的结果如下图
![5c87767082c65a5ca5473f707d417502.png](https://img-blog.csdnimg.cn/img_convert/5c87767082c65a5ca5473f707d417502.png)
所以进行解码后会出现乱码的现象。
PrintWriter
PrintWriter继承于Writer,所以可以得知PrintWriter是一个字符打印输出流。查API得知,此类实现在 PrintStream
中的所有 print 方法。它不包含用于写入原始字节的方法。
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class Test01 {
public static void main(String[] args) throws FileNotFoundException {
File file = new File("e:javateste.txt");
PrintWriter pw = new PrintWriter(file);
pw.write("hello java");
pw.flush();
pw.close();
}
}
可以通过write来对文件进行写入。和其他的字符输入流一样需要flush刷新。
如果想要写入以UTF-8的字符集写入文件,构造方法也提供了
![938e91d54f2f3e7eb86f54ad1c769fd2.png](https://img-blog.csdnimg.cn/img_convert/938e91d54f2f3e7eb86f54ad1c769fd2.png)
也可以直接用print来打印到后台显示,如下代码
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class Test01 {
public static void main(String[] args) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(System.out);
pw.print(10);
pw.close();
}
}
序列化
把内存中的对象永久保存到硬盘的过程称为对象序列化,也叫做持久化。
把硬盘持久化的内存恢复的内存的过程称为对象反序列化。
Serializable接口
类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化,并抛出异常
Exception in thread "main" java.io.NotSerializableException: cn.sxt05.serializable.Student
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at cn.sxt05.serializable.Test01.main(Test01.java:22)
假如要序列化Student对象,必须让Student类实现Serializable接口。它相当于一个标记,并没有明确指定的方法需要去实现。
public class Student implements Serializable{
// 。。。
ObjectIntPutStream和ObjectOutPutStream
ObjectIntPutStream和ObjectOutPutStream可以对对象进行序列化和反序列化。
ObjectOutputStream 继承于OutputStream,专门用于把对象序列化到本地。提供了
writeXXX
writeObject() 用于写入一个对象
public static void main(String[] args) throws IOException {
Student stu = new Student("001", "大狗", 20, Gender.男);
File file = new File("d:javatestl.txt");
FileOutputStream out = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(stu);
oos.close();
out.close();
}
ObjectInputStream 继承于InputStream ,专门用于把本地持久化内容反序列化到内存,提供了
readXXX
readObject() 用于读取一个序列化内容并返回一个对象。
比如我可以读取到stu对象序列化内容里学生的ID,名字,年龄和性别。
public static void main(String[] args) throws IOException, ClassNotFoundException {
File file = new File("d:javatestl.txt");
FileInputStream in = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(in);
Student student = (Student) ois.readObject();
System.out.println(student.getId());
System.out.println(student.getName());
System.out.println(student.getAge());
System.out.println(student.getGender());
ois.close();
in.close();
}
一般序列化完成后,如果对Student类的代码更改了,再次反序列化时就会出现异常。
Exception in thread "main" java.io.InvalidClassException: cn.sxt05.serializable.Student; local class incompatible: stream classdesc serialVersionUID = -6288733824962181189,
local class serialVersionUID = 1690603786167234505
异常原因:序列化流的serialVersionUID和升级后类的版本不匹配。
Sutdent类进行版本更新后,JVM会再自动给该类进行版本号的更新,此时与旧的版本号不一致,就会出现反序列化失败。所以要对版本号始终保持一致。
![f6fbd6a661ce266048a4c47bb772e611.png](https://img-blog.csdnimg.cn/img_convert/f6fbd6a661ce266048a4c47bb772e611.png)
public class Student implements Serializable {
private static final long serialVersionUID = -1003763572517930507L;
这里我选择默认给定的一个版本号,可以发现要用静态常量来修饰。也可以自己写一个版本号,记得写过以后不要再去修改,否则反序列化将会再次失败。
如果说开发过程中,有一些用户的隐私比如密码啥的不希望在反序列化后忽略掉,可以用到关键字transient去修饰。
public class Student implements Serializable {
private static final long serialVersionUID = 7222966748321328300L;
private String id;
private transient String name;
private transient int age;
private Gender gender;
private String phone;