IO流,序列化
JAVA(IO流,序列化)
回顾:
File类不能操作文件的内容
操作文件内容需要IO流(输入输出流)
一,IO流
按照流向分
输入流:从硬盘上读取数据打内存(读)
输出流:从内存写出数据到硬盘(写)
一个文件在传输中经历了多次拷贝,IO性能本身很低
新技术IO:零拷贝,Nio
按照操作单元分
字节流:按个字节的操作(二进制操作),可操作任意类型文件
字符流:按个字符的操作,一个字符二个字节,主要用来处理文本文件(.txt,.java,.py,.xml,.html,.css,.js)
按照角色划分
节点流:直接操作一个特定的IO设备
处理流:在结点流的基础上,做进一步的处理
JAVA中输出/输入常用的流
字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
(节点流)
缓冲流 BufferedInputStream BufferedOutputStream BufferReader BufferWriter
(处理流)
操作对象 ObjectInputStream ObjectOutputStream
二,流的使用
输入流:
一点一点的往内存读数据
InputStream inputStream =new FileInputStream("e:\\a.txt");
read方法,返回值int,返回值为-1时,文件读到了末尾
字节流读数据是一个字节一个字节读
一个流读完了就没有了,不能再读
当一个流读完之后会默认调用mark和reset方法进行记录和重置,这个流就重置到上次读完的位置,所以无法再读内容,并不是读完后就关闭
try {
InputStream inputStream =
new FileInputStream("e:\\a.txt");
int read;
while ((read = inputStream.read()) != -1){
System.out.println(read + " ");//
}
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
查看代码
@Test
public void test1(){
try {
InputStream inputStream =
new FileInputStream("e:\\a.txt");
int read;
byte[] buf = new byte[10];
while ((read = inputStream.read(buf)) != -1){
System.out.println(Arrays.toString(buf) + " ");//
}
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
字节输出流
FileOutputStream构造器
boolean append参数:如果传入true,表示从原有基础加;传入false,或者不传,覆盖原有内容
写的操作,目标文件不存在,会自己加
@Test
public void teat2(){
FileOutputStream outputStream = null;
try {
outputStream = new
FileOutputStream("e:\\a.txt",true);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
outputStream.write("123".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
案例:文件复制粘贴
//文件的复制
FileInputStream fileInputStream =
new FileInputStream("e:\\a.txt");
int read;
byte[] buf = new byte[10];
while ((read = fileInputStream.read(buf)) != -1){
System.out.println(Arrays.toString(buf) + " ");//
}
//文件的粘贴
FileOutputStream fileOutputStream =
new FileOutputStream("e:a.txt",true);
fileOutputStream.write(buf,0, buf.length);
fileInputStream.close();
复制文件
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
bufferedReader = new BufferedReader(new FileReader("e:\\a.txt"));
bufferedWriter = new BufferedWriter(new FileWriter("e:\\b.txt"));
String str;
while( (str = bufferedReader.readLine()) != null){
bufferedWriter.write(str + "\r\n");
}
bufferedReader.close();
bufferedWriter.close();
三,序列化与反序列化
(操作对象)
序列化:将对象写入到IO流中,将内存模型的对象变成字节数字,可以进行存储和传输
反序列化:从IO流中恢复对象,将存储在硬盘上或者从网络中接受的数据恢复成对象模型
使用场景:所有可在网络上 传输的对象都必须是可序列化的,否则报错,所有保存在硬盘上的对象也必须可序列化
序列化版本号:
反序列化必须拥有class文件,但随着项目的升级,class文件也会升级;序列化需保证升级前后的兼容性
java序列化提供了一个版本号,可以自己指定,如果不指定,jvm会根据类信息计算一个版本号,所以无法匹配,则报错
不指定版本号,不利于jvm的移植,可能class文件没有改,但不同jvm计算规则不一样,导致无法反序列化
如果只修改方法,反序列化是不受影响的,无需修改版本号
修改了静态变量static,瞬态变量transient,反序列化也不受影响,无需修改版本号
所有需要网络传输的对象需要实现序列化接口
对象的类名,实例变量都会被序列化;方法和类变量,transient变量不会被序列化
想让某对象不被序列化,可用transient修饰
序列化对象的引用类型成员变量,也必须是可序列化的,否则会报错
反序列化时必须有序列化对象的class文件
同一个对象被序列化多次,只有第一次序列化为二进制流,以后都只保存序列化的版本号
建议所有可序列化的类加上版本号,方便项目升级
//读取db.properties文件
Properties properties = new Properties();
properties.load(new FileInputStream("db.properties"));
System.out.println(properties.getProperty("name"));

浙公网安备 33010602011771号