这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战
Reader、Writer
字符输入流 Reader
Reader()
:创建一个新的字符流阅读器,其关键部分将在阅读器本身上同步read()
:读一个字符read(char[] cbuf)
:将字符读入数组read(char[] cbuf, int off, int len)
:将字符读入数组的一部分
字符输出流 Writer
Writer()
:创建一个新的字符流编写器,其关键部分将在编写器本身上同步append(char c)
:将指定的字符追加到此writerappend(CharSequence csq)
:将指定的字符序列追加到此writerappend(CharSequence csq, int start, int end)
:将指定字符序列的子序列追加到此writerwrite(char[] cbuf)
:写一个字符数组write(String str)
:写一个字符串write(String str, int off, int len)
:写一个字符串的一部分flush()
:刷新流
InputStreamReader、OutputStreamWriter
InputStreamReader、OutputStreamWriter 可以将字节流转换为字符流,同时指定字符编码
try {
InputStreamReader fileReader = new InputStreamReader(new FileInputStream("D:/测试用例.txt"));
OutputStreamWriter fileWriter = new OutputStreamWriter(new FileOutputStream("D:/测试用例-12.txt"), StandardCharsets.UTF_8);
int data;
while ((data = fileReader.read()) != -1) {
System.out.print((char) data);
fileWriter.write((char) data);
}
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
复制代码
FileReader、FileWriter
文件字符流 FileReader
、FileWriter
FileReader、FileWriter 值得注意的点是,只可以使用默认的字符编码,不可指定
FileReader
读取示例:
try {
FileReader fileReader = new FileReader("D:/测试用例.txt");
int data;
while ((data = fileReader.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
复制代码
FileWriter
输入示例:
try {
FileWriter fileWriter = new FileWriter("D:/测试用例.txt", true);
fileWriter.write("追加的字符串");
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
复制代码
FileReader
、FileWriter
文件字符流 实现文件拷贝
try {
FileReader fileReader = new FileReader("D:/测试用例.txt");
FileWriter fileWriter = new FileWriter("D:/测试用例-12.txt", true);
int data;
while ((data = fileReader.read()) != -1) {
System.out.print((char) data);
fileWriter.write((char) data);
}
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
复制代码
CharArrayReader、CharArrayWriter
CharArrayReader、CharArrayWriter 与字节数组字节流类似,不同的是的,单位是 char 字符,且可以指定字符编码
try {
InputStreamReader fileReader = new InputStreamReader(new FileInputStream("D:\\测试用例.txt"), StandardCharsets.UTF_8);
CharArrayWriter charArrayWriter = new CharArrayWriter();
int data;
char[] chars = new char[1024];
while ((data = fileReader.read(chars)) != -1) {
charArrayWriter.write(chars, 0, data);
}
System.out.println(charArrayWriter.toString());
} catch (IOException e) {
e.printStackTrace();
}
复制代码
StringReader、StringWriter
StringReader、StringWriter 与 CharArrayReader、CharArrayWriter 类似,只是采用了 String、StringBuffer 替代了 char 数组,当然,本质上是一样的
try {
InputStreamReader fileReader = new InputStreamReader(new FileInputStream("D:\\测试用例.txt"), StandardCharsets.UTF_8);
StringWriter stringWriter = new StringWriter();
int data;
char[] chars = new char[1024];
while ((data = fileReader.read(chars)) != -1) {
stringWriter.write(chars, 0, data);
}
System.out.println(stringWriter.toString());
} catch (IOException e) {
e.printStackTrace();
}
复制代码
BufferedReader、BufferedWriter
同样是缓冲流,字符缓冲流的使用也需要注意刷新缓冲区
try {
FileReader fileReader = new FileReader("D:\\测试用例.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
int data;
char[] chars = new char[1024];
while ((data = bufferedReader.read(chars)) != -1) {
System.out.println(new String(chars, 0, data));
}
} catch (IOException e) {
e.printStackTrace();
}
try {
FileWriter fileWriter = new FileWriter("D:\\测试用例.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write("这是字符缓冲流,注意刷新缓冲区");
bufferedWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
复制代码
PrintWriter
try {
PrintWriter printWriter = new PrintWriter("D:\\测试用例.txt", StandardCharsets.UTF_8);
printWriter.write("这是打印输出流");
printWriter.write("可以直接写入参\n数名,也支持缓冲区");
// 字符打印输出流是需要手动刷新缓冲区的
printWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}
复制代码
标准流
Scanner 类是独自存在的一个Java类,它可以接收IO流数据,并解析输出
通常清空下,Scanner是接收的标准流,在Java的使用,System.out
就是标准流的一种,标准输出流
与之对应的是标准输入流,System.in
,常见的用法为:接收输入的数据
Scanner scanner = new Scanner(System.in);
System.out.println("接收标准输入流,自键盘传入");
String str = scanner.next();
System.out.println(str);
复制代码
InputStream、OutputStream
字节输入流 InputStream
read()
:从输入流读取数据的下一个字节,若读取至末尾,则返回 -1read(byte[] b)
:从输入流读取任意字节,并将它们存储到缓冲区read(byte[] b, int off, int len)
:读取 len 字节的数据到一个字节数组close()
:关闭输入流,并释放资源
字节输出流 OutputStream
write(byte[] b)
:将 b.length字节从指定的字节数组写入此输出流write(byte[] b, int off, int len)
:从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流write(int b)
:将指定的字节写入此输出流flush()
:刷新此输出流并强制任何缓冲的输出字节被写出close()
:关闭此输出流并释放与此流相关联的任何系统资源
InputStream、OutputStream 作为字节流的抽象父类存在,具体的实现请看之后
FileInputStream、FileOutputStream
文件字节流 FileInputStream
、OutputStream
文件字节流是 节点流
,可以直接读、写数据
FileOutputStream
:写入数据到硬盘中
单字节写入
try {
FileOutputStream stream = new FileOutputStream("D:/测试用例.txt");
// main 程序的一次运行视为一次数据的写入
stream.write('H');
stream.write('W');
} catch (IOException e) {
e.printStackTrace();
}
复制代码
多字节写入,以字节数组的形式
try {
FileOutputStream stream = new FileOutputStream("D:/测试用例.txt");
String str = "多个文字组成的字符串";
// 将字符串转化为字节数组
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
stream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
复制代码
单字节读取
try {
FileInputStream stream = new FileInputStream("D:/测试用例.txt");
int data;
while ((data = stream.read()) != -1) {
// 将整数再转换为对应的字符
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
复制代码
多字节读取
try {
FileInputStream stream = new FileInputStream("D:/测试用例.txt");
int data;
byte[] bytes = new byte[1024];
while ((data = stream.read(bytes)) != -1) {
// 输入出字符,一次最多输出 1024
System.out.print(new String(bytes, 0, data));
}
} catch (IOException e) {
e.printStackTrace();
}
复制代码
文件字节流,实现文件拷贝
try {
FileInputStream inputStream = new FileInputStream("D:/测试用例.txt");
FileOutputStream outputStream = new FileOutputStream("D:/测试用例-12.txt");
int data;
byte[] bytes = new byte[1024 * 4];
while ((data = inputStream.read(bytes)) != -1) {
// 写入数据的同时,打印内容
System.out.print(new String(bytes, 0, data));
outputStream.write(bytes, 0, data);
}
} catch (IOException e) {
e.printStackTrace();
}
复制代码
ByteArrayInputStream、ByteArrayOutputStream
在之前的文件字节流中,存在一个问题,不能够一次性读取完文件数据
简单的理解,若一个字符正好是被分成了两个字节数组,则输出的时候就可能出现乱码
ByteArrayInputStream、ByteArrayOutputStream,则是为文件字节流设置了一个缓冲,可以存储每次读取的数据,最后一次输出完毕
try {
FileInputStream inputStream = new FileInputStream("D:\\测试用例.txt");
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1) {
// 存储文件字节流读取的数据
arrayOutputStream.write(bytes, 0, len);
}
// 最后读取完毕时,一次输出
System.out.println(arrayOutputStream.toString(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
复制代码
DateInputStream、DateOutputStream
之前的字节流中,只是以字节为单位,进行数据的读出、写入
DateInputStream、DateOutputStream 则是支持以不同的类型读出、写入,例如 int、long,设置是自定义的 Java 类
这里,一个 Java 类的实例对象为例,读出写入的方式
Person 类
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
复制代码
将 Java 类对象写入到硬盘中
Person person = new Person("里斯", 23);
try {
FileOutputStream outputStream = new FileOutputStream("D:\\测试用例.txt");
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF(person.getName());
dataOutputStream.writeInt(person.getAge());
} catch (IOException e) {
e.printStackTrace();
}
复制代码
将 Java 类对象读取到内存中
try {
FileInputStream inputStream = new FileInputStream("D:\\测试用例.txt");
DataInputStream dataInputStream = new DataInputStream(inputStream);
String name = dataInputStream.readUTF();
int age = dataInputStream.readInt();
System.out.println(name);
System.out.println(age);
} catch (IOException e) {
e.printStackTrace();
}
复制代码
可以很清晰的看到,字节流不仅仅是使用字节为单位进行传输的,也可以直接写入、读出 Java 类
这里面涉及到了Java对象的序列化机制,可以再被写入数据的文件中发现,文字是以乱码的形式表现的
BufferedInputStream、BufferedOutputStream
BufferedInputStream、BufferedOutputStream 是字节缓冲输入流,可以为字节读出、写入提供缓冲区的支持
简单的理解,由字节缓冲流包装的文件字节流,可以将读出、写入的数据暂时缓存,最后再输出、写入
可能会觉得,缓冲字节流与字节数组流相似,但字节数组流内部并不存在缓冲区,只是功能效果上的类似
try {
FileInputStream inputStream = new FileInputStream("D:/测试用例.txt");
FileOutputStream outputStream = new FileOutputStream("D:/测试用例-12.txt", true);
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
int data;
byte[] bytes = new byte[1024];
while ((data = bufferedInputStream.read(bytes)) != -1) {
System.out.print(new String(bytes, 0, data));
bufferedOutputStream.write(bytes, 0, data);
}
// 刷新缓冲区,否则数据不会被写入到硬盘中
bufferedOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
复制代码
值得注意的是,当数据写入到硬盘中时,必须刷新缓冲区 flush()
缓冲字节流的存在,使得无须频繁的读出、写入,但缓冲字节流无法直接操作数据,它是处理流,而非节点流