【Java】—IO:流、字节流
一、什么是流?
1.1 概念
流,指的是数据在硬盘
和内存
之间的传输通道,是一种抽象概念。
从数据的交换方向上来分,流分为输入流
和输出流
。
输入流:数据从硬盘传输到内存。(硬盘 -> 内存)
输出流:数据从内存传输到硬盘。(内存 -> 硬盘)
需要处理异常:
FileNotFoundException
IOException
1.2 图例演示
1.3 分类
流的分类方式有许多种。
一、按 方向
分类:
- 输入流:将数据从存储设备
读取
到内存中的流。 - 输出流:将数据从内存
写入
到存储设备中的流。
二、按 数据处理单位
分类:
- 字节流:每次读取或写入数据的基本单位是
字节
的流。 - 字符流:每次读取或写入数据的基本单位是
字符
的流。
字节流和字符流的使用情况:
如果处理二进制文件,使用字节流
。
例:图像、音频、视频、class字节码文件。
如果处理文本数据,使用字符流
。
例:.txt、.java、.html。
如果想要按行读取数据,使用字符流
。
三、按 功能
分类:
- 节点流:具有实际传输数据能力的流。
- 过滤流: 在节点流的基础之上增强了功能的流。
二、文件字节流
2.1 概念
最基本的处理文件数据的字节流
文件字节流有两个类,分别代表输入和输出两种功能:FileInputStream
和FileOutputStream
。
FileInputStream
:文件字节输入流
FileOutputStream
:文件字节输出流
FileOutputStream有两个构造方式:
-
一参构造:FileOutputStream(String path)
特点:如果path指定的文件存在,之后写入时会覆盖此文件。 -
二参构造:FileOutputStream(String path,boolean append)
特点:如果path指定的文件存在,之后写入时会将数据追加。
2.2 创建对象
第一种:
FileInputStream fis = new FileInputStream("D:\\文件测试\\1.txt");//构造方法可以接收字符串形式的地址
FileOutputStream fos = new FileOutputStream("D:\\文件测试\\1.txt");
第二种:
File file = new File("D:\\文件测试\\1.txt");
FileInputStream fis = new FileInputStream(file);//构造方法可以接收File类型
File file = new File("D:\\文件测试\\1.txt");
FileOutputStream fis = new FileOutputStream(file);
2.3 方法
2.3.1 read()
作用:读取单个字节,返回其ASCLL码,如果到达文件的末尾,返回-1
所需类型:FileInputStream
返回值类型:int
缺点:无法读取汉字,因为汉字至少占2
字节,读取后会出现乱码。
磁盘中:
代码演示:
File file = new File("D:\\文件测试\\1.txt");
FileInputStream fis = new FileInputStream(file);
int n = fis.read();//从文件中读取一个字节,并以byte形式输出
System.out.println((char)n);
运行结果:
H
2.3.2 read(byte[ ] buf)
作用:根据数组buf的长度,在其中添加数据,并返回添加数据的数量。如果没有数据,返回-1
所需类型:FileInputStream
返回值类型:int
磁盘中:
代码演示:
File file = new File("D:\\文件测试\\1.txt");
FileInputStream fis = new FileInputStream(file);
byte[] b = new byte[20];
int len = fis.read(b);//将获取到的数据放入byte数组b中,并返回字节的数量
System.out.println("字节个数:");
System.out.println(len);
System.out.println("读取数据:");
System.out.println(new String(b).substring(0,len));//由于数据可能没有装满数组b,所以需要通过获取的长度len精确捕获
运行结果:
字节个数:
11
读取数据:
HelloWorld!
2.3.3 read(byte[ ] b,int offset,int len)
作用:从文件中读取字节,在文件的当前指针开始读len个字节,并将其存储在b数组中,存储的位置在b的offset下标开始,然后返回此次读取的数据的长度。如果文件中没有数据,返回-1。
所需类型:FileIputStream
返回值类型:int
磁盘中:
代码演示:
FileInputStream fis = new FileInputStream("D:\\文件测试\\1.txt");
byte[] b = new byte[100];
b[0] = 97;//埋下伏笔
int len = fis.read(b,1,30);//在文件中,从b数组下标1的位置赋值30个字节数据,并返回实际数据长度
System.out.println("数据长度:");
System.out.println(len);
System.out.println("数据:");
System.out.println(new String(b).substring(0,len / 3));//第一个数据为a,因为前面赋值过
//编码格式为utf-8,一个汉字占3个字节,所以除以3
运行结果:
数据长度:
18
数据:
a你好,世界!
2.3.4 write(byte[ ] b)
作用:将字节数组b中的内容写入文件,如果文件中有数据,则会全部覆盖。
注意事项:在同一个线程中,写入文件中的数据会堆叠,不会覆盖,只会覆盖线程启动前的文件。
所需类型:FileOutputStream
磁盘中:
代码演示:
File file = new File("D:\\文件测试\\1.txt");
FileOutputStream fop = new FileOutputStream(file);
FileInputStream fip = new FileInputStream(file);
byte[] b = new byte[100];
int len;
String s1 = "I am Tiger";
fop.write(s1.getBytes());//存储字母
len = fip.read(b);//将读取的数据存入b数组中
System.out.println(new String(b).substring(0,len));//显示读取的数据
String s2 = "你好世界";
fop.write(s2.getBytes());//存储汉字
len = fip.read(b);//将读取的数据存入b数组中
System.out.println(new String(b).substring(0,len));
fip.close();//养成好习惯,用完就关闭
fop.close();
运行结果:
磁盘前后变化:
存入字母:
数据覆盖了
存入汉字:
数据堆叠了
三、对象流
3.1 概念
专门用于读取和写入对象的字节流。其中写入对象叫做对象序列化
,读取对象叫做对象反序列化
。
对象序列化
:将对象写入文件中。
对象反序列化
:将对象从文件中读取出来。
若想实现序列化和反序列化,需要对象所在类实现接口:Serializable
。
以学生类为例:
public class Student implements Serializable{//只有实现Serializeble接口才能进行对象流操作。
//内部内容省略不写
}
对象字节流有两个类,分别代表输入和输出两种功能:ObjectInputStream
和ObjectOutputStream
。
ObjectInputStream
:对象字节输入流
ObjectOutputStream
:对象字节输出流
3.2 创建对象
第一种:
FileInputStream fis = new FileInputStream("D:\\文件测试\\1.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
FileOutputStream fos = new FileOutputStream("D:\\文件测试\\1.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
第二种:
File file = new File("D:\\文件测试\\1.txt");
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
File file = new File("D:\\文件测试\\1.txt");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
第三种:
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\文件测试\\1.txt"));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\文件测试\\1.txt"));
3.3 方法
3.3.1 writeObject(Object obj)
作用:将对象obj存入文件中,对象所在类需要实现
Serializable
接口。
所需类型:ObjectOutputStream
代码演示:
Student类中:
public class Student implements Serializable{//Student类实现了Serializable接口
String name;
int age;
String gender;
Student(String name,int age,String gender){
this.name = name;
this.age = age;
this.gender = gender;
}
}
main()中:
File file = new File("D:\\文件测试\\1.txt");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student stu1 = new Student("张三",18,"男");
oos.writeObject(stu1);
oos.flush();//将数据从缓存区中写入文件
fos.close();//用完了就关闭,养成好习惯
oos.close();
磁盘中:
3.3.2 readObject(Object obj)
作用:将对象从文件中取出,取出的对象类型为Object,需要进行向下转型。对象所在类需要实现
Serializable
接口。
所需类型:ObjectInputStream
磁盘中:
代码演示:
Student类中:
public class Student implements Serializable{//Student类实现了Serializable接口
String name;
int age;
String gender;
Student(String name,int age,String gender){
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
main()中:
File file = new File("D:\\文件测试\\1.txt");
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Student stu = (Student)ois.readObject();//从文件中读取对象
System.out.println(stu);
运行结果:
Student{name=‘张三’, age=18, gender=‘男’}
四、字节缓冲流
4.1 概念
比起文件字节流效率更加高,自带缓冲区,提高IO效率。
特点:
- 提高IO效率,减少访问磁盘的次数。
- 数据存储在缓冲区中,
flush
是将缓存区中的内容写入文件中,也可以直接close
。
字节缓冲流有两个类,分别代表输入和输出两种功能:BufferedInputStream
和BufferedOutputStream
。
BufferedInputStream
:对象字节输入流
BufferedOutputStream
:对象字节输出流
4.2 创建对象
第一种:
FileInputStream fis = new FileInputStream("D:\\文件测试\\1.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("D:\\文件测试\\1.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
第二种:
File file = new File("D:\\文件测试\\1.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
File file = new File("D:\\文件测试\\1.txt");
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
第三种:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\文件测试\\1.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\文件测试\\1.txt"));
4.3 方法
4.3.1 write(byte b[ ])
作用:将数组b写入文件中。
所需类型:BufferedOutputStream
代码演示:
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\文件测试\\1.txt"));
String s = "Who are you";
bos.write(s.getBytes());//只能存储字符类型数据,所以需要转换
bos.flush();//此时数据在缓冲区中,使用flush方法将其真正写入文件
bos.close();//养成随手关门的好习惯
磁盘中:
4.3.2 read()
作用:将文件读取出来
所需类型:BufferedInputStream
代码演示:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\文件测试\\1.txt"));
byte[] b = new byte[1024];//1KB
int len = bis.read(b);
System.out.println("数据长度:");
System.out.println(len);
System.out.println("读取的数据:");
System.out.println(new String(b).substring(0,len));//精确获取数据
运行结果:
数据长度:
11
读取的数据:
Who are you
总结
这篇文章总结了IO流中的字节流及其下属分类各流。