IO流相关概念
IO流
1.1概念
对文件中的内容进行操作。IO:针对文件的内容操作的一个类的集合。
File只能对文件进行操作,但是但是无法对文件中的内容进行操作。
1.2 IO分类
依据流的方向:这个方向是相对于程序来说的,而不是相对应文件来说的。
- 输入流:读取文件的内容
- 输出流:输出到文件中
依据流的内容
- 字节流(8位字节):可用处理一切文件,本身没有缓冲区
- 字符流(16位字节):只能处理纯文本文件的文本内容,本身带有缓冲区
1.3 字节流
1.3.1字节输出流
字节输出流的父类:OutputStream,它是所有字节输出流的父类,它是一个抽象类。最常见的子类FileOutputStream
实现效果:通过调用字节输出流的方法,往文件中输入内容。
程序—内容—》文件
实现步骤:
-
创建一个字节输出流。参数:创建一个文件对象(文件地址),布尔值-是否追加内容
该流默认覆盖原本的内容
-
要处理异常,因为文件路径可能因为不存在或找不到而出现异常
-
定义一个变量用来赋值要向文件输入的内容,String类型
-
调用输出功能——write()方法。输出内容必须为字节类型,所以要转化为字节getBytes()。
-
在finally方法体里关闭流close(),要处理异常
-
因为流可能为空,当不为空时关闭。
public static void main(String[] args) {
//1.创建字节输出流
OutputStream os=null;//便于后面处理异常
try {
os=new FileOutputStream(new File("174.txt"),true);//允许追加内容,处理异常
String msg="武陵人捕鱼为业";//要输出的内容
os.write(msg.getBytes());//使用write方法输出,要将字符串类型转化为字节
} catch (Exception e) {
e.printStackTrace();
}finally {
//关闭流,处理异常,因为流可能为空
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.3.2 字节输入流
以字节的方式读取文件中的内容。读取到程序中(内存中)。
字节输入流的父类InputStream,它里面包含操作字节的方法,也是一个抽象类。最常见的子类:FileInputStream
实现效果:通过调用字节输入流,将指定文件的内容读取输入到程序中。
程序《—内容—文件
一个汉字为两个字节,所以通过字节输入流读取到的汉字为乱码
实现步骤:
- 创建一个字节输入流对象,参数:创建一个文件对象,值为文件地址
- 处理异常,因为路径可能会出现异常
- 通过调用read()方法读取文件内容,每次读取一个字节,获得相应字节的字节码,并将其返回。如果没有内容则返回-1。
- 所以初始值变量赋值为-1;通过while循环,判断==(a=is.read())==的值,当不等于-1时,进入循环。
- 此时得到的为整型字节码。需要强转为字符型char,再依次输出字符。
- 关闭字节输入流close(),在finally里面关
public static void main(String[] args) {
InputStream is=null;//创建字节输入流,处理异常
try {
is=new FileInputStream(new File("174.txt"));//取哪个文件的内容
//创建变量,赋值-1;假设文件没有内容
int a=-1;
//循环,通过read方法判断
while ((a=is.read())!=-1){
//将字节码转为相应字符
char c=(char) a;
//输出
System.out.print(c);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流,处理异常
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
1.3.3案例——复制
通过字节流完成文件的复制
实现效果:通过字节输入流获取到文件的内容,再通过字节输出流将文件内容输出到指定的文件,以此达到复制的效果。
实现步骤:
- 创建字节输入流,读取指定文件的内容
- 创建输出流,指定输出到哪个文件中
- 设置变量,存储字节码的值,初始值为-1
- 通过while循环,判断==(a=is.read())不等于-1,有内容进入循环体,循环体内字节流输出write()==方法。
- 关闭流
public static void main(String[] args) {
InputStream is=null;
OutputStream os=null;//便于处理异常
try {
is=new FileInputStream(new File("D:\\AAAAAAAA\\learn\\2.JavaScript\\图\\1.png"));
os=new FileOutputStream(new File("D:\\2.png"));
int a=-1;
while ((a=is.read())!=-1){
//读一个写一个
os.write(a);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
1.4 字符流
1.4.1字符输出流
Write类,它是所有字符输出流的父类,输出的内容以字符为单位,也是抽象类。常用的子类为:FileWrite类
实现效果:通过调用字符输出流,实现向文件中输出字符内容
实现步骤:
- 创建一个字符输出流如果文件不存在,该流会自动创建相应文件
- 参数:文件对象地址,布尔值是否追加
- 创建变量,赋值要添加的内容
- 通过==write()==方法将内容输出到指定文件中。因为该方法参数有字符串类型,所以不用类型转换
- 关闭流,要处理异常
public static void main(String[] args) {
//创建字符输出流
Writer w=null;
//处理异常
try {
w=new FileWriter(new File("D:\\1.txt"));
//要输出的内容
String str="你好李焕英";
w.write(str);//write参数有字符串类型
} catch (Exception e) {
e.printStackTrace();
}finally {
if(w!=null){
try {
w.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
1.4.2 字符输入流
Reader是字符输入流的一个父类,也是抽象类。常见的子类FileReader,以字符为单位
实现效果:通过调用字节输入流,读取文件的内容,并将其输入到程序中
实现步骤:
- 创建一个字符输入流,处理异常
- 参数指定要读取的文件的地址。
- 读取的单位为一个字符,如果没有内容,返回的结果为-1。
- 通过while循环判断,(a=r.read())!=-1进入循环体
- 将整型强转为字符型,输出
- 关闭流,处理异常
public static void main(String[] args) {
Reader r=null;//处理异常
try {
r=new FileReader(new File("D:\\1.txt"));
//取值
int a=-1;
while ((a=r.read())!=-1){
char c=(char) a;//强转
System.out.print(c);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流
if(r!=null){
//处理异常
try {
r.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
1.4.3 案例——复制
实现效果:通过字符输入流和字符输出流将文本纯文本内容取出和输入,达到复制的效果
实现步骤:
- 创建字符输入流
- 创建字符输出流,处理异常
- 将文件的文本内容取出,通过read()方法
- 通过while循环,将取出的内容,在循环体内,通过write()方法,将内容输出到指定文件。
- 关闭流,处理异常
public static void main(String[] args) {
//创建字符输入流,字符输出流
Reader rd=null;
Writer wt=null;
try {
rd=new FileReader(new File("D:\\oop笔记1.txt"));
wt=new FileWriter(new File("D:\\3.txt"));
int a=-1;
while ((a= rd.read())!=-1){
wt.write(a);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (rd!=null){
try {
rd.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(wt!=null){
try {
wt.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意编码问题,若记事本编码为ANSI,需将其改为UTF-8后才可以进行转换,否则会出现乱码
1.5 处理流——缓冲流
缓冲流,也叫高效流,是对应4个基本的FileXXX流的增强,所以也是4个流,按照数据类型分类:
-
字节缓冲流:BufferedInputStream和BufferedOutputStream,缓冲流是作用在流上的。
-
字符缓冲流:BufferedReader和BufferedWriter
程序—输出流—缓冲流–——》文件
基本原理:在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率
1.5.1 字节缓冲流
- 缓冲字节输入流BufferedInputStream:创建一个新的缓冲输入流
- 参数(InputStream in)
- 实现步骤:
- 创建一个字节输入流i,处理异常
- 创建缓冲字节输入流(i),处理异常
- 通过read方法读取文件的内容
public static void main(String[] args) {
//创建字节输入流
InputStream is=null;
//创建缓冲字节输入流
BufferedInputStream bis=null;
//处理异常
try {
is=new FileInputStream(new File("174.txt"));
bis=new BufferedInputStream(is);
//读取
int a=-1;
while ((a= bis.read())!=-1){
char ch=(char) a;
System.out.print(ch);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流
if(bis!=null){
try {
bis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
- 缓冲字节输出流:BufferedOutputStream,创建一个新的缓冲输出流
- 参数(OutputStream out)
- 实现步骤:
- 创建一个字节输出流
- 创建一个缓冲字节输出流
- 处理异常
- 创建变量存放要输出的内容
- write方法写入,类型转换为字节getBytes()
- 关闭缓冲区,有顺序,要先关闭缓冲流,刷新缓冲区,将缓冲区的内容取出,才可以将内容写入文件。然后再字节流。
public static void main(String[] args) {
//创建字节输出流
OutputStream os=null;
//创建缓冲字节输出流
BufferedOutputStream bos=null;
//处理异常
try {
os=new FileOutputStream(new File("174.txt"),true);
bos=new BufferedOutputStream(os);
//创建变量,赋值要输出的内容
String str="晋太元中,武陵人捕鱼为业";
//要转为字节型,输出
bos.write(str.getBytes());
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流有顺序,要先关闭缓冲区,刷新缓冲区,将缓冲区的内容取出来
if(bos!=null){
try {
//刷新缓冲区
bos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//关闭字节输出流
if(os!=null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
- 提供效率
- 使用缓冲流实现赋值,提高效率
public static void main(String[] args) {
//开始时间
long l = System.currentTimeMillis();
//创建字节输入流
InputStream is=null;
//创建缓冲字节输出流
BufferedInputStream bis=null;
//创建字节输出流
OutputStream os=null;
//创建缓冲字节输出流
BufferedOutputStream bos=null;
//处理异常
try {
is=new FileInputStream(new File("E:\\录屏File\\1.mp4"));
bis=new BufferedInputStream(is);
os=new FileOutputStream(new File("D:\\1.mp4"));
bos=new BufferedOutputStream(os);
//读
int a=-1;
while ((a=bis.read())!=-1){
bos.write(a);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(bis!=null){
try {
bis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(bos!=null){
try {
bos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(os!=null){
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
//结束时间
long l1 = System.currentTimeMillis();
System.out.println(l1-l);
}
1.5.2 字符缓冲流
- 缓冲字符输入流:BufferedReader,创建一个新的缓冲输入流
- 参数(Reader in);
public static void main(String[] args) {
//创建字符输入流
Reader r=null;
//创建缓冲字符输入流
BufferedReader br=null;
//处理异常
try {
r=new FileReader(new File("174.txt"));
br=new BufferedReader(r);
//取值
int a=-1;
while ((a=br.read())!=-1){
char ch=(char) a;
System.out.print(ch);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(r!=null){
try {
r.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(br!=null){
try {
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
- 缓冲字符输出流:BufferedWriter,创建一个新的缓冲输出流
- 参数(Writer out)
public static void main(String[] args) {
//创建字符输出流
Writer w=null;
//创建缓冲字符输出流
BufferedWriter bw=null;
//处理异常
try {
w=new FileWriter(new File("174.txt"),true);
bw=new BufferedWriter(w);
String str="缘溪行,忘路之远近,忽逢桃花林";
bw.write(str);
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流,先关缓冲流,刷新缓冲区
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(w!=null){
try {
w.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
- 提供效率
public static void main(String[] args) {
//创建字符输入流
Reader r=null;
//创建缓冲字符输入流
BufferedReader br=null;
//创建字符输出流
Writer w=null;
//创建缓冲字符输出流
BufferedWriter bw=null;
//处理异常
try {
r=new FileReader(new File("D:\\1111.txt"));
br=new BufferedReader(r);
w=new FileWriter(new File("D:\\12.txt"));
bw=new BufferedWriter(w);
//取出
int a=-1;
while ((a= br.read())!=-1){
bw.write(a);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流
if(br!=null){
try {
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(r!=null){
try {
r.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(w!=null){
try {
w.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
- 特有方法:
- BufferedReader的方法:readLine(),读一行文字
- BufferedWriter的方法:newLine(),写一行 行分隔符,有系统属性定义符号。
1.6对象流
操作 Java类对象。把Java类对象写入到文件中,或者从文件中读取写入的Java对象。
强大之处:把内存中的对象存到硬盘中
1.6.1 序列化
序列化:把内存中的Java对象写入到文件中的过程,即程序输出
用**ObjectOutputStream**类从内存中的Java对象保存到磁盘中或通过网络传输出去
- 序列化机制: 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
序列化后,并不能查看,是乱码,如需查看需要用反序列化机制
- 自定义类实现序列化需要满足的条件
- 自定义类需要实现接口:Serializable
- 当前类提供一个全局常量:serialVersionUID
- 除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
- ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
1.6.2 反序列化
反序列化:把文件中的对象读取到内存中,将磁盘文件中的对象还原为内存中的一个Java对象,程序输入
用ObjectInputStream类从硬盘读取到内存
1.6.3 实例
实现步骤:
-
自定义一个类,实现接口Serializable
-
定义序列化方法——程序输出
若某个类实现了Serializable接口,该类的对象就是可序列化的
①创建一个ObjectOutputStream
②调用 ObjectOutputStream对象的writeObject(对象)方法输出可序列化对象
③注意写出一次,操作flush()一次,刷新缓存区
-
定义反序列化方法——程序输入
①创建一个ObjectInputStream
②调用readObject()方法读取流中的对象
-
强调:如果某个类的属性不是基本数据类型或String类型,而是另外一种引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的Field的类也不能序列化。
-
在main方法中调用上述方法。
//Student类
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重写toString方法
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
//Test测试类
public static void main(String[] args) {
//Student s=new Student("张三",19);
//write();
read();
}
//序列化
public static void write() {
//创建字节输出流
OutputStream is=null;//可不创建
//创建对象输出流
ObjectOutputStream oos=null;
//处理异常
try {
//要写入的文件
is=new FileOutputStream(new File("175.txt"));
oos=new ObjectOutputStream(is);
//把一个java对象写入文件时要求该对象所在的类必须实现序列化接口
oos.writeObject(new Student("张三",19));
oos.flush();//刷新
oos.writeObject(new Student("李斯",18));
oos.flush();//刷新
}catch (Exception e){
e.printStackTrace();
}finally {
if(oos!=null){
try {
oos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
//反序列化
public static void read(){
//创建字节流输入流
InputStream is=null;
//创建对象输入流
ObjectInputStream ois=null;
//处理异常
try{
is=new FileInputStream(new File("175.txt"));
ois=new ObjectInputStream(is);
//创建一个对象来接收
//Object o=ois.readObject();
Student s=(Student) ois.readObject();
Student s1=(Student) ois.readObject();
System.out.println(s);
System.out.println(s1);
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流
if(ois!=null){
try {
ois.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}