导读
在文件I/O这一节的知识里,对文件的操作主要分为两大类:
☑️针对文件系统进行的操作
☑️针对文件内容进行的操作
上文已经讲了针对文件系统即File类的操作,这篇文章里博主就来带了解针对文件内容的操作,即输入输出流(Reader,Writer,InputStream,OutputStream)四种流相关知识📖
前置知识
1、流的分类
文件I/O中的流分为字节流和字符流
字符流:以字符为单位,每次读写的最小单位是字符;对应文本文件。包括Reader,Writer两个类
字节流:以字节为单位,每次读写的最小单位是字节;对应二进制文件。包括InputStream,OutputStream两个类
流的关系分类如下图
注意,字符和字节的关系如下
一个字符可能是对应多个字节
GBK,一个中文字符 ->两个字节
UTF8,一个中文字符 ->三个字节
2、输入输出的定义
计算机中的输入输出发生在CPU和硬盘之间,而我们所说的输入输出是以CPU为视角,即
· 把数据从CPU保存到硬盘上,是输出/写(Input/Read)
· 把内容从硬盘取到CPU里,是输入/读(Output/Write)
下图可以形象地表示输入输出的定义
四种流的使用
1、Reader
(1)Reader类
先创建一个Reader
Reader reader = new FileReader("/Users/liuwenwen/Desktop/test.txt");
(2)Reader类中的方法
Reader最常用的就是read方法,read方法分为下面几种
方法名 | 说明 |
read(char[] cbuf) | 传入数组参数,读取数组长度的字符存放在数组中 |
read () | 读一个字符 |
read(CharBuffer target) | 传入CharBuffer对象 |
read(char[] cbuf,int off, int length) | 传入数组参数,从字符串off位置开始读,读取length长度的字符存放在数组中 |
(3)代码实例
其中最常用的是read(char[] cbuf)方法,返回参数是读取字符的个数
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class demo {
public static void main(String[] args){
char[] buf = new char[12];
try(Reader reader = new FileReader("/Users/liuwenwen/Desktop/test.txt")) {
while (true){
int n = reader.read(buf);
if(n == -1){
break;
}
System.out.println("n="+n);
for (int i = 0; i < n; i++) {
System.out.print(buf[i]);
}
System.out.println();
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
注意:代码中将Reader reader = new FileReader("/Users/liuwenwen/Desktop/test.txt放在try()代码块中是隐藏了reader.close()操作,相当于
try {
Reader reader = new FileReader("/Users/liuwenwen/Desktop/test.txt")
while (true){
int n = reader.read(buf);
if(n == -1){
break;
}
System.out.println("n="+n);
for (int i = 0; i < n; i++) {
System.out.print(buf[i]);
}
System.out.println();
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}finally{
reader.close();
}
读取结果
2、Writer类
(1)Writer中的方法
Writer方法如下
方法名 | 说明 |
write(String str) | 一次写一个字符串 |
write(char[] cbuf) | 一次写多个字符(字符数组) |
write(int c) | 一次写一个字符 |
write(String str, int off, int len) | 带有 offset 和lenoffset指的是从字符串中的第几个字符开始写 |
write(char[] cbuf, int off, int len) | 带有 offset 和lenoffset 指的是从数组中的第几个字符开始写 |
(2)代码实例
我们最常用的是第一个即write(String str)方法
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class demo3 {
public static void main(String[] args) {
try(Writer writer = new FileWriter("/Users/liuwenwen/Desktop/test.txt")) {
writer.write("驻跸怀千古,开襟望九州。太平词藻盛,长愿纪鸿休。");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
运行程序后,文本内容被修改了😦
可见我们原来的内容同时也被覆盖。如果不想覆盖原本的内容,怎么办呢?🤔
在创建Writer类时,加一个参数true,表示追加
try(Writer writer = new FileWriter("/Users/liuwenwen/Desktop/test.txt",true))
为了防止由于程序运行太快,内容在缓冲区中没有来得及写到硬盘里,我们加一个flush()方法
writer.flush();
现在整体代码就变成
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class demo3 {
public static void main(String[] args) {
try(Writer writer = new FileWriter("/Users/liuwenwen/Desktop/test.txt",true)) {
writer.write("驻跸怀千古,开襟望九州。太平词藻盛,长愿纪鸿休。");
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
用原来的文本再次运行程序
可以看到,这次是追加,不再是覆盖
3、InputStream类
(1)方法
InputStream类和Reader类里的方法类似,不过将char[]数组变为了byte[]数组,返回值是读取字节的个数
(2)代码实例
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class demo5 {
public static void main(String[] args) {
try (InputStream inputStream = new FileInputStream("/Users/liuwenwen/Desktop/test.txt")){
byte[] buf = new byte[1024];
int n = inputStream.read(buf);
for (int i = 0; i < n; i++) {
System.out.printf("%x ",buf[i]);
//采用十六进制打印,更加直观
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
读取结果
4、OutputStream类
(1)方法
OutputStream类和Writer类里的方法类似,不过将char[]数组变为了byte[]数组
(2)代码实例
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class demo6 {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("/Users/liuwenwen/Desktop/test.txt",true)){
String s = "驻跸怀千古,开襟望九州。太平词藻盛,长愿纪鸿休。";
outputStream.write(s.getBytes());
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
由于OutputStream类write方法要传入的是byte[]参数,我们直接调用字符串的getBytes()方法,方便书写
最终追加结果