流对象
1.字节流(对应二进制文件)
每次读写最小单位是“字节”
InputStream
OutputStream
2.字符流(对应文本文件)
每次读写最小单位是“字符”(utf8中1中文字符3字节 GBK中1中文字符2字节)
(字符流相当于对字节流的封装 自动把文件中相邻的几个字节转换成一个字符)
Reader
Writer
Reader
public abstract class Reader//抽象类 不能new实例 只能new子类
Reader reader=new FileReader("d:/test.txt");//创建Reader对象的过程,就是打开文件的过程
①无参 一次读取一个字符
②一个参数 一次读取若干个字符 会把数组填满
③三个参数 一次读取若干个字符 会把数组从off位置开始 len长度结束尽量填满
传入一个空的字符数组,read对数组进行填充,像cbuf这种参数称为“输出型参数”
char[] cbuf=new char[1024];
reader.read(cbuf);
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
Reader reader=new FileReader("d:/test.txt");
try{
//一次读取一个字符
// while(true){
// int c=reader.read();
// if(c==-1)
// break;
// System.out.println("1");
// System.out.println((char)c);
//
// }
//一次读取多个字符
while(true){
System.out.println("2");
char[] cbuf=new char[3];
int c= reader.read(cbuf);
if(c==-1)
break;
System.out.println("2");
for(int i=0;i<3;i++){
System.out.print(cbuf[i]);
}
}
}
finally{
//关闭文件
reader.close();
}
}
}
close()释放文件描述符,文件描述符是一个顺序表(数组),一个进程每次打开一个文件,旧就需要在表里分配一个元素,如果一直打开文件不关闭,会把数组占满,再尝试打开文件时会出错
此处介绍一个更优雅的做法
try(Reader reader2=new FileReader("d:/test.txt")){
while(true){
System.out.println("2");
char[] cbuf=new char[3];
int c= reader.read(cbuf);
if(c==-1)
break;
System.out.println("2");
for(int i=0;i<3;i++){
System.out.print(cbuf[i]);
}
}
}
try with resources会在try代码块结束的时候(正常结束/抛出异常),会自动调用close()方法
要求()中的对象实现Closeable接口 (流对象都实现了)
Writer
Writer writer=new FileWriter("d:/test.txt",true);//加上true 写入文件末尾 不会清空原有内容
如何将字节流转为字符流?
InputStream inputStream=new FileInputStream("d:/test.txt");
PrintWriter writer2=new PrintWriter(outputStream);
writer2.write("aaa");
//变成我们熟悉的print
writer2.println("aaa");
writer2.print("Hello");
writer.printf("%d: %s\n", 1, "没什么");
writer2.flush();
数据先被写入有内存构成的缓冲区 再写入硬盘中
但如果写入缓冲区后没来得及写入硬盘进程结束了,那么数据会丢失,为了避免这种情况,手动使用flush方法(刷新缓冲区),手动刷新缓冲区,确保数据写入硬盘