FileInputStream-----FileOutputStream
BufferedInputStream-----BufferedOutputStream
FileReader-----FileWriter
BufferedReader-----BufferedWriter
InputStreamReader-----OutputStreamReader (过度流 把字节流->转成字符流)
PrintStream-----PrintWriter(不需要捕获异常 自动刷新缓冲区 提供println方法)
ObjectInputStream ------ObjectOutputStream(必须实现 Serializable接口)
字节流(以Stream结尾)是指8位(1字节)的通用字节流,以字节为基本单位,在java.io包中,对于字节流进行操作的类大部分继承于InputStream(输入字节流)类和OutputStream(输出字节流)类;
字符流(以Reader或则Writer结尾)是指16位(2字节)的Unicode字符流,以字符(两个字节)为基本单位,非常适合处理字符串和文本,对于字符流进行操作的类大部分继承于Reader(读取流)类和Writer(写入流)类。
流的常用方法
FileInputStream
指定文件打开输入流对象 读取文件内容 一次读取一个字节 文件指针指向末尾返回-1
一次读取一个字节
try {
//指定文件打开输入流对象 读取文件内容 一次读取一个字节 文件指针指向末尾返回负一
InputStream fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\aa\\date.txt");
//一次读取一个字节
int read = 0;
while (read != -1) {
System.out.println((char) fis.read());
read = fis.read();
}
//关闭流
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
一次读取多个字节
try {
//指定文件打开输入流对象 读取文件内容 一次读取一个字节 文件指针指向末尾返回负一
InputStream fis = new FileInputStream("C:\\Users\\Administrator\\Desktop\\aa\\date.txt");
byte[] b = new byte[10];//缓冲区长度
int len=0;
while ((len=fis.read(b))!=-1){//从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。
String a = new String(b,0,len);//防止多读数据 b[]数组不会清空
System.out.println(a);
}
//关闭流
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
FileOutPutStream
向文件中写入 默认从第一个位置添加,会覆盖原来的所有数据 true 代表 在文件数据尾部追加不会覆盖
写入文件
try {
//向文件中写入 true 代表在文件数据尾部追加
FileOutputStream fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\aa\\date.txt");
fos.write('a');//一次写入一个字符
fos.write("hellow世界".getBytes());//一次写入一个字符数组
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
BufferedInputStream
具体用法和BufferedReader相似
读取一个字符(不能读取一行 因为 ‘\n’ 是一个字符 其无法识别回车 所以不能读一行)
try {
BufferedInputStream br = new BufferedInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\aa\\aa.txt"));
System.out.println(br.read());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
一次读取多个字符
try {
BufferedInputStream br = new BufferedInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\aa\\aa.txt"));
byte[] str = new byte[10];
int len;
while ((len=br.read(str))!=-1){//read()返回值为-1
System.out.println(new String(str));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
BufferedOutputStream
写入一个字符
try {
BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\aa\\wri.txt"));
bw.write('o');
bw.flush();//不写close() 数据在缓存中无法刷新到磁盘 则调用flush()将数据刷新到磁盘
bw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
FileReader
读取一个字符
try {
FileReader fw = new FileReader("C:\\Users\\Administrator\\Desktop\\aa\\copy\\RISKWRITENIN.txt");
System.out.println((char) fw.read());//读取一个字符返回该字符的ASII值将其强转换为字符,如果已到达流的末尾,则返回 -1
fw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
单个打印所有字符
try {
FileReader fw = new FileReader("C:\\Users\\Administrator\\Desktop\\aa\\copy\\RISKWRITENIN.txt");
int read;
while ((read=fw.read())!=-1){
System.out.println((char) read);
}
fw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
多个读取
try {
FileReader fr = new FileReader("C:\\Users\\Administrator\\Desktop\\aa\\copy\\writer.txt");
char[] str = new char[10] ;
fr.read(str);//一次读取10个字符 将字符写入str[]中 返回值为读到数据的长度到末尾返回-1
System.out.println(new String(str));//将字符转成字符串输出
fr.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
按行打印所有字符
try {
FileReader fr = new FileReader("C:\\Users\\Administrator\\Desktop\\aa\\copy\\writer.txt");
char[] str = new char[10];
int len = 0;
//一次读取10个字符 将字符写入str[]中 返回值为读到数据的长度
while ((len = fr.read(str))!=-1){
//数组不会清空 避免多余的数据需要根据读取到的数组长度来输出
System.out.println(new String(str, 0, len));
}
fr.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
FileWriter
一次写入一个字符
try {
FileWriter fw = new FileWriter("C:\\Users\\Administrator\\Desktop\\aa\\copy\\writer.txt", true);
fw.write("helloWorld");//一次写入一个字符串
fw.close();
} catch (IOException e) {
BufferedReader
读取一行字符
try {
FileReader fr = new FileReader("C:\\Users\\Administrator\\Desktop\\aa\\copy\\小说.txt");
BufferedReader br = new BufferedReader(fr);
System.out.println(br.readLine());//一次读取文本一行返回得到的字符串,读到文件末尾返回null
br.close()
fr.close()
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
按行打印文本全部字符
try {
FileReader fr = new FileReader("C:\\Users\\Administrator\\Desktop\\aa\\copy\\小说.txt");
BufferedReader br = new BufferedReader(fr);
String str;
while ((str = br.readLine())!=null) {
System.out.println(str);//一次读取一行,读到文件末尾返回null
}
br.close()
fr.close()
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
BufferedWriter
写一字符到文件
try {
//文件不存在则创建该文件
FileWriter fw = new FileWriter("C:\\Users\\Administrator\\Desktop\\aa\\copy\\writer.txt");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("helloWorld123");//写入一个字符串
bw.close();//不关闭写不进去
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
写多个字符到文件
try {
BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\aa\\wri.txt",true));
String str = "helloWorld";
bw.write(str.getBytes());
bw.flush();//不写close() 数据在缓存中无法刷新到磁盘 则调用flush()将数据刷新到磁盘
bw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
InputStreamReader OutputStreamWriter
转换流
当输入对象时字节流 但是输出时字符流时可以用转换流
例如从控制台输入文字都是字节流 但是将其打印确实字符流 这时可以用到转换流
try {
//字节输入流转成字符输入流
//等价于FileReader 只不过数据是从控制台输入的
//相当于Scanner scanner = new Scanner(System.in);
InputStreamReader isr = new InputStreamReader(System.in);
char b[] = new char[10];
int read = isr.read(b);//一次最多读取十个字符到b[]中 返回读取到的字符数量
System.out.println("字符输入流:" + new String(b, 0, read));
//字符缓冲流
BufferedReader br = new BufferedReader(isr);
//从isr的缓冲区读取数据,读取到回车或则文件末尾 将读取到的值返回,函数结束
//当isr的缓冲区没有值时,readLine()将会重新接收控制台输入的数据
String bt = br.readLine();
System.out.println("字符缓冲流:"+bt);
br.close();//读没有刷新 关闭防止占用资源
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
PrintStream PrintWriter
使用输出流在控制台输出
// System.in 字节输入流
//System.out 字节输出流 不用捕获异常 自动刷新
//PrintWriter 字符输出流 不用捕获异常 可以调自动刷新
//输入设备和输出设备都是字节的 所以没没有PrintReader
try {
System.out.write("123".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
//true 代表自动刷新
PrintStream ps = new PrintStream(System.out,true);
ps.println("kukku");
PrintWriter pw = new PrintWriter(System.out, true);
pw.println("kukku");
pw.close();
new PrintWriter(System.out, true).println("hahaha");//System.out.println();
}
ObjectOutputStream
把对象写入文件的过程 叫做对象序列化
1、要序列化的对象必须实现Serializable 否则无法写入到文件中 实现该接口后(勾选 idea ->Editor->Inspections->勾选 Serializable class without serialVersionUID )可以在类中看到serialVersionUID (防止对象发生改变时(增加或删除一个属性值反序列化会报错))
private static final long serialVersionUID = 8049979471748042621L;
2、把对象写入文件的过程 叫做对象序列化 从文件读取对象叫做 对象反序列化
3、当属性不想被序列化时 在该属性前面写上transient 序列化后读取该对象的该属性值为null
private int id;//可序列化
private transient String name;//属性不想被序列化
4、序列化底层原理:把对象分解成二进制存入文件中例如存入 int(10)、byte(1)存放二进制为
0000 0000 0000 0000 0000 0000 0000 1010 0000 0001
序列化对象
writeByte writeShort writeInt writeUTF(字符串序列化)…
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\aa\\obj.txt"));
//将对象以二进制写入文件中
oos.writeByte(10);//1字节
oos.writeShort(11);//2字节
oos.writeInt(212);//4字节
oos.writeChar('a');//4字节
oos.writeFloat(3.14f);//4字节
oos.writeLong(100);//8字节
oos.writeDouble(215);//8字节
oos.writeUTF("你好世界");//字符串序列化
oos.writeBoolean(true);//1字节
//对象必须实现Serializable 把对象写入文件的过程 叫做对象序列化 从文件读取对象叫做 对象反序列化
oos.writeObject(new Student(10, 25, "张三"));
ArrayList<Student> list = new ArrayList<>();
list.add(new Student(10, 25, "张三2"));
list.add(new Student(11, 25, "李四"));
list.add(new Student(12, 25, "王五"));
oos.writeObject(list);
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
ObjectInputStream
从文件读取对象叫做 对象反序列化
!!!反序列化要注意 取值顺序和存值顺序要一致
当放入不一致时例如放入int(10),用四个byte来读取时得到的数据是0 0 0 10 原理为:
0000 0000(第一个byte截取到0) 0000 0000 (第二个byte截取到0)0000 0000 (第三个byte截取到0)0000 1010(第四个byte截取到10)
对象反序列化
注意要点:当对已经存在的序列化对象进行反响序列化时 在类中对某个序列化对象的属性上进行增加一个属性或者删除一个属性 这时若无serialVersionUID 属性则在反序列化时报错 必须实现接口得到该序列化id
readShort readInt readChar readUTF(符串对象反序列化)…
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\aa\\obj.txt"));
ois.skipBytes(1);//跳过一个字节 表示不反系列化一个byte字符
System.out.println(ois.readShort());//
System.out.println(ois.readInt());
System.out.println(ois.readChar());
System.out.println(ois.readFloat());
System.out.println(ois.readLong());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
System.out.println(ois.readBoolean());
System.out.println(ois.readObject());
((ArrayList<Student>)ois.readObject()).stream().forEach(s-> System.out.println(s));
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
RandomAccessFile
随机访问文件流比较灵活,属于字节流。
随机访问文件流,可以指定读和写
读写操作与对象流一样
“r” 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
“rw” 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
“rws” 打开以便读取和写入,对于 “rw”,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
“rwd” 打开以便读取和写入,对于 “rw”,还要求对文件内容的每个更新都同步写入到底层存储设备。
构造方法:
- RandomAccessFile(File file, String mode)
- RandomAccessFile(String name, String mode)
RandomAccessFile raf = new RandomAccessFile("C:\\Users\\Administrator\\Desktop\\aa\\raf.txt", "rw");
写操作
raf.writeByte(10);
raf.writeShort(20);
raf.writeInt(30);
raf.writeLong(50);
raf.writeChar('a');
raf.writeFloat(60.1f);
raf.writeDouble(70.1);
raf.writeBoolean(false);
System.out.println("当前指针位置:" + raf.getFilePointer());
raf.writeUTF("abcc你好");//占3个字节多占两个字节
System.out.println("当前指针位置:" + raf.getFilePointer());
读操作
//把文件指针移动到前边
//读文件
//根据写入的顺序读取 跟对象流一样
raf.seek(0);
System.out.println(raf.readByte());
System.out.println(raf.readShort());
System.out.println(raf.readInt());
System.out.println(raf.readLong());
System.out.println(raf.readChar());
System.out.println(raf.readFloat());
System.out.println(raf.readDouble());
System.out.println(raf.readBoolean());
System.out.println(raf.readUTF());
总结
总的来说IO分为:输入流,输出流,数据大小为:字节、字符
1、字节输出流直接将数据写入到磁盘
2、字节缓冲输出流和其他字符流输出流先把数据放在缓冲区 在进行flush()或者close()时会把缓冲区数据刷新输出
3、字节流可以对一切文件进行操作 字符流只能处理字符和字符串
4、什么时候用到转换流:当输入对象时字节流 但是输出为字符流时可以用转换流,例如从控制台输入文字都是字节流 但是将其打印却是字符流 这时可以用到转换流
5、关闭流避免占用内存 注意其关闭顺序按照
- 先打开的流先关闭
- 按照依赖关系:例如a依赖b则先关闭b再关闭a
- 直接关闭处理流 例如BufferedWriter的构造方法需要其他的流对象,则可以直接关闭BufferedWriter。
补充
System.out.print(流对象 没有引用值 不用开关流 jvm自动回收) 用checkerror解决异常抛出