IO流
IO概述
- 概述:IO是input和output的缩写。
输入和输出,表示的是数据的输入和数据的输出。 - 什么是输入和输出?
数据的输入和输出就是相对于运行内存来说,数据从其他设备进入到运行内容就是输入,数据从运行内容到其他设备就是输出。 - 凡是操作数据输入和输出的对象所属的类型,都属于IO的范围。
- 分类:
按照功能和流向有不同的类型
按照功能分类:
字节流
字符流
按照流向分类:
输入流
输出流 - 具体分类:
字节输入流:inputStream ;字节输出流:outputStream
字符输入流:Reader ;字符输出流:Writer
IO使用范围
- 导包:IO范围的类型都在io包中,需要先导包
- 处理异常:声明或者捕获
- 关流:关闭系统资源,节省资源
字节流
- 概述:操作字节信息输入和输出的流对象所属的类型。
- 字节输入流inputStream 字节输出流outputStream
InputStream
- 概述:字节输入流,本类是一个抽象父类,不能直接创建对象,需要通过子类创建
- 方法:
-read() :从流中读取一个字节信息,将信息进行返回。
注意:当前方法返回的是一个int类型的数据,而不是一个byte类型
原因:默认在读取的字节信息前面加了24个0,强制变为一个int类型。因为读取的信息是一个字节信息,字节范围-128–127,如果读取了一个-1,可能是读取的数据,也可能是到达文件的末尾,所以为了区分是读取的数据,还是到达了文件的末尾,就默认在读取的数据前+20个0,强制变为正数,当读取返回了一个-1,肯定是到达了文件的末尾。
-read(byte[] b) :从流对象中一次读取b.length个字节
注意:
(1)读取的数据存储到了到数组中
(2)返回值是读取的字节个数
-read(byte[] b, int off, int len) :从流中读取指定长度的数据到数组中
-available() :将流中还没有读取的字节个数进行返回
-close() :关闭流资源
FileInputStream
- 概述:属于字节输入流的子类,该类的对象可以将磁盘上的文件数据输入到内存中。
- 构造方法:
(1)FileInputStream(File file):将file文件对象封装为文件字节输入流对象
(2)FileInputStream(String str) :将str字符串所描述的文件封装为字节输入流对象 - 注意事项:
不管是传入file对象还是字符串,对应的必须是某一个文件,不能是文件夹
原因:因为文件中才可以存储数据,文件夹中不能直接存储数据,所以只能从文件中读取数据。
OutputStream
- 概述:字节输出流,将字节信息从内存中写出到其他设备。也是一个抽象类,需要通过子类创建对象。
- 方法:
-write(int b) :将一个字节信息写出内存
-write(byte[] b) :将一个数组中的信息写出内存
-write(byte[] b, int off, int len) :将数组中的一部分信息写出内容
-close() :关闭流资源
FileOutputStream
- 概述:文件字节输出流,将字节信息从内存中写出到目标磁盘文件中。
- 构造方法:
-FileOutputStream(File file) :将file对象封装为一个字节输出流对象
-FileOutputStream(String name) :将name字符串对应的文件封装为字节输出流对象
-FileOutputStream((File file,boolean b) :将name字符串对应的文件封装为字节输出流对象,如果后面的值为false,表示替换写入信息
-FileOutputStream(String name,boolean b) :将name字符串对应的文件封装为字节输出流对象,如果后面的值为true,表示追加写入信息 - 注意:
不管是传入file对象还是字符串,对应的必须是某一个文件,不能是文件夹
原因:因为文件中才可以存储数据,文件夹中不能直接存储数据,所以只能从文件中读取数据。
文件的copy
- 文件拷贝:将一个文件中的信息,复制到另外一个文件中
- 思路:
先通过文件字节输出流将信息读取到内存中,再通过文件字节输出流将信息写出到另外一个目标文件中
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("a_copy.txt");
int i ;
while((i=fis.read())!=-1) {
fos.write(i);
}
fis.close();
fos.close();
}
}
文件拷贝效率提升
- 拷贝效率慢原因:
一个字节需要IO两次,读一次写一次,如果要拷问的字节有很多,需要iO文件个数两倍的次数。 - 提升思路:
一次多读几个字节,多写几个字节。使用read(byte[] b)的方法和write(byte[] b)的方法,多读几个多写几个来提升效率。 - 使用大数组拷贝问题:
数组将来需要再虚拟机中开辟空间, 如果数组的大小太大,将来对空间的要求比较高,可能空间也不够用,所以不能使用大数组拷贝。所以只能使用小数组拷贝文件。 - 使用小数组拷贝问题:
但是使用小数组拷贝数据的时候,应该是读几个数据写出几个数据,所以需要使用write(byte[] b,0,len)这个方法来写出数据,避免多写出数据,造成发生数据的错误。 - 注意:
使用小数组拷贝文件,一般指定数组的大小一般为1024的整数倍。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("maa.mp4");
FileOutputStream fos = new FileOutputStream("maa2.mp4");
byte[] bs = new byte[1024*8];
int length ;
while((length=fis.read(bs))!=-1) {
fos.write(bs,0,length);
}
fis.close();
fos.close();
}
}
高效缓冲字节流
- 高效缓冲字节输入流:BufferedInputStream
- 高效缓冲字节输出流:BufferedOutPutStream
- 概述:这两个类型是包装类型,本类的对象不能读取和写出数据,但是这两个类型可以对基础的流对象进行加强(包装),加强之后,可以默认一次读取多个数据,写出多个数据,因为这两个类型中都维护了一个数组,来完成文件的拷贝。
- 构造方法:
BufferedInputStream(InputStream in) :将基础的字节输入流对象进行包装成为一个高效字节输入流
BufferedOutputStream(OutputStream out) :将基础的字节输出流对象进行包装
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo01 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("maa.mp4");
FileOutputStream fos = new FileOutputStream("maa3.mp4");
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int i ;
while((i=bis.read())!=-1) {
bos.write(i);
}
bis.close();
bos.close();
}
}
close和flush的区别
- close方法作用:
(1)可以将数据从缓冲区中刷新到目标文件中
(2)可以关闭流资源 - flush方法作用:
(1)只能将数据从缓冲区刷新到目标文件中 - 两者关系:
在使用close方法关闭流资源之前,系统会默认调用flush方法先刷新数据
字符流
使用的原因
- 如果想要一次写一个字符串,使用字节流可以完成,但是需要将字符串进行转换为字节数组。(操作稍微有点麻烦)
- 如果想要从一个文件中读取信息,进行展示
(1)这个文件中如果是全英文,可以一次读取一个字节,进行转换
(2)如果全是中文,可以使用字节流一次读取两个字节,将两个字节转为一个字符串,进行展示
(3)如果文件中是中英文混杂,这时不知道是读取几个字节进行转换,容易发生乱码。
概述
- 字符流:可以以字符为单位操作数据的输入和输出的对象所属的类型
- 分类
字符输入流 Reader
字符输出流 Writer
Reader
- 字符输入流,也是一个抽象父类,不能直接创建对象
- 方法:
-read() :读取一个字符信息,将读到的信息进行返回
-read(char[] c) :读取c.length个字符到数组中,返回的是读取的字符个数
-read(char[] c,int offset,int len):读取一部分字符到数组中
-close() :关闭流资源 - 使用子类创建对象:FileReader
-FileReader(File file)
-FileReader(String fileName) - 不仅可以读取全中文以及全英文,还可以读取中英文混杂的字符。
Writer
- 字符输出流,是一个抽象父类,不能直接创建对象
- 方法:
-write(int c) :写出一个字符
-write(String str) :写出一个字符串
-write(char[] cbuf) :写出一个数组中的字符
-write(char[] cbuf, int off, int len) :写出数组的一部分到目标文件
-write(String str, int off, int len) :写出字符串的一部分 - FileWriter:文件字符输出流
-FileWriter(File file)
-FileWriter(String fileName) - 注意:
(1)写出的目标必须是一个文件,不能是一个文件夹
(2)字符输出流类型中,也是维护了一个数组,使用之后,需要使用刷新方法或者关流方法,将数据刷新到目标文件中
文件的copy
- 思路:先通过字符输入流将字符信息读取到内存中,再通过字符输出流将信息从内存写出到目标文件中。
- 使用的场景:
如果只需要拷贝文件,使用字节流拷贝即可
如果需要查看某个文件中的信息,或者修改某个文件中的信息,使用字符流来读,来写出信息。
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("a_copy.txt");
int i;
while((i=fr.read())!=-1) {
fw.write(i);
}
fr.close();
fw.close();
}
}
字符流使用小数组拷贝文件
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("b.txt");
FileWriter fw = new FileWriter("b_copy.txt");
char[] ch = new char[1024*8];
int i;
while((i=fr.read(ch))!=-1) {
fw.write(ch,0,i);
}
fr.close();
fw.close();
}
}
字符流拷贝非纯文本文件
- 纯文本文件:全是以字符的方式来表示数据的文件
- 非纯文本文件:图片,视频,音频等不是以字符的方式来表示数据的文件
- 结论:字符流不能拷贝非纯文本文件
- 原因:
使用字符流拷贝数据的话,需要先通过字节流将字节信息输入到内存中,再通过查询编码表将字节信息转成对应的字符。非纯文本文件中都很多字节,读取的字节信息不一定和编码表中的字符对应,如果没有字符对应这个读取的字节,使用?字符来代替。在写出的时候,继续将?对应的字节写出到了目标文件中。
高效缓冲字符流
- 类型:BufferedReader和BufferedWriter
- 概述:都是包装类型,需要对基础的字符流对象进行包装。包装之后,一次也可以读取多个字符,可以写出多个字符。
- 构造:BufferedReader(Reader in)
方法:readLine() :一次可以从输入流中读取一行信息
返回值就是读取的这一行数据,如果到达文件的末尾,返回null - 构造:BufferedWriter(Writer out)
方法:newLine() :表示在文件中进行换行