IO 概述
1. IO的分类
根据数据的流向:输入流和输出流
根据数据的类型:字节流和字符流
2. 顶级父类
输出流 | 输入流 | |
---|---|---|
字节流 | OutputStream | InputStream |
字符流 | Writer | Reader |
字节流
1. 字节输出流 -> OutputStream
主要方法:
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。public void write(byte[] b)
:将 b.length字节从指定的字节数组写入此输出流。public void write(byte[] b, int off, int len)
:从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。public abstract void write(int b)
:将指定的字节输出流。
2.通过字节流写一个文件
public static void writeFIleByOutPutStream() throws IOException {
// 创建一个输出流对象
FileOutputStream fos = new FileOutputStream("1.txt");
// 向文件中写入字节数据
fos.write("这是一个字节输出流写的文件".getBytes());
fos.close();
}
3. 字节输入流 -> InputStream
public void close()
:关闭此输入流并释放与此流相关联的任何系统资源。public abstract int read()
: 从输入流读取数据的下一个字节。public int read(byte[] b)
: 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。
4. 通过字节输入流读取文件
public static void readFileByInputStream() throws IOException {
// 创建一个字节输入流
FileInputStream fis = new FileInputStream("1.txt");
// 定义一个字节数组
byte[] bytes = new byte[1024];
// 定义一个有效长度变量
int len;
// 开始读取文件
while ((len = fis.read(bytes)) != -1) {
// 输出
System.out.println(new String(bytes, 0, len));
}
// 关闭资源
fis.close();
}
5. 通过字节流复制一个文件
public static void main(String[] args) throws IOException {
// 创建一个文件字节输入流
FileInputStream fis = new FileInputStream("C:\\Users\\WH\\Desktop\\高等数学(II-2).docx");
// 创建一个文件字节输出流
FileOutputStream fos = new FileOutputStream("这是字节流程复制的文件-1.docx");
// 定义有效个数变量
int len;
// 定义一个1024 长度的字节数组
byte[] chars = new byte[1024];
// 开始读取文件,并写入 输出流
while ((len = fis.read(chars)) != -1) {
fos.write(chars,0, len);
System.out.println(new String(chars, 0, len));
}
fos.close();
fis.close();
}
字符流
1. 字符输出流程 -> Writer
void write(int c)
写入单个字符。void write(char[] cbuf)
写入字符数组。abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分,off数组的开始索引,len写的字符个数。void write(String str)
写入字符串。void write(String str, int off, int len)
写入字符串的某一部分,off字符串的开始索引,len写的字符个数。void flush()
刷新该流的缓冲。void close()
关闭此流,但要先刷新它。
2. 通过字符输出流创建写一个文件
public static void writeFileByFileWriter() throws IOException {
// 创建一个 字符输出流程对象
FileWriter fw = new FileWriter("2.txt");
// 写出数据
fw.write(97); // 写出第1个字符
fw.write('b'); // 写出第2个字符
fw.write('C'); // 写出第3个字符
fw.write(30000); // 写出第4个字符,中文编码表中30000对应一个汉字。
fw.write("\r\n".toCharArray());
// 刷新缓冲区
fw.flush();
// 写入字符数组
char[] chars = "这是一个字符数组".toCharArray();
fw.write(chars);
fw.write("\r\n".toCharArray());
// 刷新缓冲区
fw.flush();
// 写入字符串
fw.write("这是一个字符串");
fw.write("\r\n");
fw.close();
}
小贴士:
- 虽然参数为int类型四个字节,但是只会保留一个字符的信息写出。
- 未调用close方法,数据只是保存到了缓冲区,并未写出到文件中。
- 即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。
关闭和刷新
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush
方法了。
flush
:刷新缓冲区,流对象可以继续使用。close
:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
3. 字符输入流 -> Reader
public void close()
:关闭此流并释放与此流相关联的任何系统资源。public int read()
: 从输入流读取一个字符。public int read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
4. 通过字符输入流程读取一个文件
public static void readFileByFileReader() throws IOException {
// 创建一个 字符输入流
FileReader fr = new FileReader("2.txt");
// 创建一个字符数组
char[] chars = new char[1024];
int len;
System.out.println("通过字符数组读取==========================================");
while ((len = fr.read(chars)) != -1) {
System.out.println(new String(chars));
}
System.out.println("通过字符读取==========================================");
// 创建一个 字符输入流
FileReader fr2 = new FileReader("2.txt");
int b;
while ((b = fr2.read()) != -1) {
System.out.println((char) b);
}
fr.close();
}
写出换行
- 回车符
\r
和换行符\n
:
- 回车符:回到一行的开头(return)。
- 换行符:下一行(newline)。
- 系统中的换行:
- Windows系统里,每行结尾是
回车+换行
,即\r\n
;- Unix系统里,每行结尾只有
换行
,即\n
;- Mac系统里,每行结尾是
回车
,即\r
。从 Mac OS X开始与Linux统一。
缓冲流
1. 概述
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强,所以也是4个流,按照数据类型分类:
-
字节缓冲流:
BufferedInputStream
、BufferedOutputStream
-
字符缓冲流:
BufferedReader
、BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
2. 字节缓冲流
2.1 构造方法
public BufferedInputStream(InputStream in)
:创建一个 新的缓冲输入流。public BufferedOutputStream(OutputStream out)
: 创建一个新的缓冲输出流。
2.2 使用缓冲流改造字节流
public static void copyFileByBufferedStream() throws IOException {
// 创建一个缓冲字节输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\WH\\Pictures\\屏幕截图 2020-12-29 230816.png"));
// 创建一个缓冲字节输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("图片-copy-buffered.png"));
// 定义有效个数变量
int len;
// 定义一个1024 长度的字节数组
byte[] byte= new byte[1024];
// 开始读取文件,并写入 输出流
while ((len = bis.read(byte)) != -1) {
bos.write(chars,0, len);
}
bos.close();
bis.close();
}
3. 字符缓冲流
3.1 构造方法
public BufferedReader(Reader in)
: 创建以新的缓冲输入流public BufferedWrite(Writer out)
: 创建一个新的缓冲输出流
3.2 特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
- BufferedReader:
public String readLine()
: 读一行文字。 - BufferedWriter:
public void newLine()
: 写一行行分隔符,由系统属性定义符号。
3.3 通过readLine()
读取文件
public static void readFileByBufferedReader() throws IOException {
// 创建一个 字符输入缓冲流
BufferedReader br = new BufferedReader(new FileReader("2.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
System.out.println("===============================");
}
br.close();
}
3.4 通过字符缓冲流复制一个文件
public static void copyFileByBufferedStream() throws IOException {
// 创建一个 字符输入缓冲流
BufferedReader br = new BufferedReader(new FileReader("2.txt"));
// 创建一个 字符输出缓冲流
BufferedWriter bw = new BufferedWriter(new FileWriter("copy-2.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
System.out.println("===============================");
bw.write(line);
bw.newLine();
}
bw.close();
br.close();
}
转换流
1. 概述
字符编码
计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。
编码:字符(能看懂的)–字节(看不懂的)
解码:字节(看不懂的)–>字符(能看懂的)
2. InputStreamReader
-> 字节流通向字符流的桥梁
2.1 构造函数
InputStreamReader(InputStream in)
:创建一个使用系统默认字符集的字符流InputStreamReader(InputStream in, String charsetName)
:创建指定字符集字符流
2.2 指定字符集读取文件
public static void readFile() throws IOException {
// 创建一个 字节转换字符流
InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\WH\\Desktop\\gb2312.txt"));
// 默认字符集读
int len;
char[] chars = new char[1024];
System.out.println("默认字符集读文件============================");
while ((len = isr.read(chars)) != -1) {
System.out.println(new String(chars));
}
// 创建一个 字节转换字符流
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("C:\\Users\\WH\\Desktop\\gb2312.txt"),"gb2312");
System.out.println("指定gb2312字符集读文件============================");
char[] read = new char[1024];
while ((len = isr2.read(read)) != -1) {
System.out.println(new String(read));
}
isr.close();
isr2.close();
}
3. OutputStreamWriter
-> 字符流到字节流的桥梁
3.1 构造方法
OutputStreamWriter(OutputStream in)
: 创建一个使用默认字符集的字符流。OutputStreamWriter(OutputStream in, String charsetName)
: 创建一个指定字符集的字符流。
3.2 指定编码写文件
public static void writeFile() throws IOException {
// 创建一个指定字符的流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
// 向文件中写数据
osw.write("你好");
osw.flush();
osw.close();
// 创建一个不指定字符的流对象
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("no-gbk.txt"));
// 向文件中写数据
osw2.write("你好");
osw2.flush();
osw2.close();
}
4. 图解
InputStreamReader
读取字节,解码为字符
字节 -------------------------------------> 字符
OutputStreamWriter
写出字符,编码为字节