1. IO流
1.1 流Stream
- 只能单方向流动
- 输入流in–输出流out–从程序角度
- 数据只能从头到尾的 顺序读写一次
1.2 IO流继承结构
1.2.1 File文件流
封装磁盘路径字符串,创建可操作对象
1.2.2 父类
不可创建对象–学习父类提供的共性方法–通过子类创建可以操作的对象
InputStream–OutputStream–字节输入输出流 --针对二进制文件
Reader–Writer–字符输入输出流–针对文本文件
1.2.3 子类
FileInputeStream BufferedInputStream ObjectInputStream
FileOutputeStream BufferedOutputStream ObjectOutputStream
FileReader BufferedReader InputStreamReader
FileWriter BuffererdWriter OutputStreamWrite
FileInputeStream–直接插在文件上,直接读取文件数据
BufferedInputStream创建对象
BufferedInputStream(InputStream in)
创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
实例化:
InputStream in2 =new BufferedInputStream(new FileInputStream("D:\\ready\\1.txt"));
1.2.4 文件复制综合案例
package cn.tedu.file;
//测试文件复制案例
import java.io.*;
import java.util.Scanner;
/**
* 需求:接受用户输入的文件路径来进行复制,复制到用户指定的路径下
*/
public class TestCopyFile {
public static void main(String[] args) {
//1.提示并接收两个路径
System.out.println("请输入源文件路径");
String f = new Scanner(System.in).nextLine();
System.out.println("请输入目标文件路径");
String t = new Scanner(System.in).nextLine();
//2. 把接收到的路径进行封装变成可以进行文件操作的File对象
File from = new File(f);
File to = new File(t);
//3. 调用复制方法进行复制
ZJCopy(from, to);//自定义字节流复制文件的方法
//ZFCopy(from, to);//自定义字符流复制文件的方法
}
public static void ZJCopy(File from, File to) {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(from));
out = new BufferedOutputStream(new FileOutputStream(to));
int a = 0;
while ((a = in.read()) != -1) {
out.write(a);
}
System.out.println("文件复制完成");
} catch (Exception e) {
System.out.println("文件复制失败");
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void ZFCopy(File from, File to) {
//注意局部变量需要初始化,null
Reader in = null;//定义整个方法都生效的字符输入流抽象父类类型的变量
Writer out = null;
try {
//通过输入流读取from--获取字符输入流对象
in = new BufferedReader(new FileReader(from));
//通过输出流输出to--获取字符输出流对象
out = new BufferedWriter(new FileWriter(to));
//定义变量--边读边写
int a = 0;
while ((a = in.read()) != -1) {
out.write(a);//将本轮循环内容写出
}
System.out.println("文件复制完成");
} catch (Exception e) {
System.out.println("文件复制失败");
e.printStackTrace();
} finally {
/**1. 流资源必须释放,释放的是之前使用过程中所以的流对象
* 2. 关流是有顺序的,注意:后创建的先关流,为了不影响其他的代码,不能先关最先创建的流*/
try {
out.close();//关闭字符输出流
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();//关闭字符输入流
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.3 序列化与反序列化
1.3.1 概述
序列化:利用ObjectOutputStream,把对象信息按照固定格式转换成一串字节输出并持久保存到磁盘
反序列化:利用ObjectIntputStream,读取磁盘中之前序列化好的数据,从新恢复成对象
1.3.2 特点/应用场景
- 需要序列化的文件必须实现Serializable接口,用来启用序列化功能
- 不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出
- 每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个
- 在反序列化时,如果和序列化的版本号不一致,无法完成反序列化
- 常用与服务器之间的数据传输,序列化成文件,反序列化读取数据
- 常用使用套接字流在主机之间传递对象
- 不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存
1.3.3 案例
创建封装学生类
package cn.tedu.seri;
import java.io.Serializable;
//封装学生类
/**本类如果想要实现序列化,必须实现可序列化接口,否则报错
* 报错信息:NotSerializableException: cn.tedu.seri.Student
* Serializable是一个空接口,里面一个方法都没有,
* 作用:当作标志,标志着这个类可以被序列化*/
public class Student implements Serializable {
/**需要给每个进行序列化的文件分配唯一的UID值*/
//private static final long serialVersionUID = 1l;//默认存在
//1.定义并封装属性--提供get,set方法
private int sno;//学号
private String name;//姓名
private String address;//住址
private char gender;//性别
//2.提供无参构造--必须手动提供午餐构造,否则会被含参构造覆盖
public Student() {
System.out.println("Student的无参构造");
}
//3.全参构造
public Student(int sno, String name, String address, char gender) {
this.sno = sno;
this.name = name;
this.address = address;
this.gender = gender;
System.out.println("Student的全参构造");
}
public int getSno() {
return sno;
}
public void setSno(int sno) {
this.sno = sno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
/**打印结果:cn.tedu.seri.Student@4dd8dc3
* 查看属性值,重写toString*/
@Override
public String toString() {
return "Student{" +
"sno=" + sno +
", name='" + name + '\'' +
", address='" + address + '\'' +
", gender=" + gender +
'}';
}
}
测试序列化与反序列化
package cn.tedu.seri;
import java.io.*;
//测试序列化与反序列化
public class TestSerializable {
public static void main(String[] args) {
method();//测试序列化
method2();//测试反序列化
}
/**序列化方法*/
public static void method() {
//声明在本方法中生效的系列化类型的变量,局部变量需要初始化--null
ObjectOutputStream out = null;
try {
//1.创建用来序列化的流对象OOS
out = new ObjectOutputStream(new FileOutputStream("D:\\ready\\1.txt"));
//2.创建Student对象
Student s = new Student(666,"泡泡","地球村",'男');
//3.通过OOS流对象来序列化对象输出到指定文件
out.writeObject(s);
System.out.println("序列化成功");
}catch (Exception e){
System.out.println("序列化失败");
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**反序列化*/
public static void method2() {
ObjectInputStream in =null;
try {
in = new ObjectInputStream(new FileInputStream("D:\\ready\\1.txt"));
Object o =in.readObject();
System.out.println(o);
System.out.println("反序列化成功");
}catch (Exception e){
System.out.println("反序列化失败");
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意:
-
序列化对象所在类要实现序列化接口
public class Student implements Serializable { -
UID要保持一致或者序列化与反序列化同时操作,否则会报错
手动添加UID,只要这个值不改变,就可以不论次数编译,进行序列化和反序列化操作
private static final long serialVersionUID = 1l;
本文深入讲解Java中的IO流概念及其实现方式,包括文件流、缓冲流等,并提供了文件复制的具体实现案例。此外,还详细介绍了序列化与反序列化的原理及应用。
1万+

被折叠的 条评论
为什么被折叠?



