一. 字符流
字节流:适合复制文件等,不适合读写文本文件
字符流:适合读写文本文件内容
1. FileReader(文件字符输入流)
作用:以内存为基准,可以把文件中的数据以字符的形式读入到内存中去。读取单个字符,性能比较差,一次读取多哥字符,性能还是不错的鸭。
package com.file;
import java.io.FileReader;
import java.io.Reader;
public class FileTest12 {
public static void main(String[] args) {
try (
//1、创建一个文件字符输入流管道与源文件接通
Reader fr = new FileReader("day07/src/com/file/test/test.txt");
) {
System.out.println("===一次读取一个字节===");
int c;
while ((c=fr.read())!=-1){
char temp = (char) c;
System.out.print(temp);
}
System.out.println("\r\n===一次读取多个字节===");
char[] chars = new char[3];
//2、读取文本文件的内容
//记住每次读取的字符个数
int read;
while ((read=fr.read(chars))!=-1){
String s = new String(chars, 0, read);
System.out.print(s);
}
}catch (Exception exception){
exception.printStackTrace();
}
}
}
2. FileWriter(文件字符输出流)
作用:以内存为基准,把内存中的数据以字符的形式写出到文件中去。
- 字符输出流写出数据后,必须刷新流,或者关闭流,写出去的数据才能生效
- 数据会先写到缓冲区里面,最后通过机制调用一次直接写出到磁盘中,性能会变好的
- 刷新流:flush方法,刷新后流还可以继续使用的,缓冲区装满好会自动flush,缓冲区强制刷新到输出文件中
- 关闭流:close方法 包含刷新流 关闭后流不可以继续使用了
- 数据会先写到缓冲区里面,最后通过机制调用一次直接写出到磁盘中,性能会变好的
字节流、字符流的使用场景小结
- 字节流适合做一切文件数据的拷贝(音视频,文本);字节流不适合读取中文内容输出符流适合做文本文件的操作(读,写)。
package com.file;
import java.io.FileWriter;
import java.io.Writer;
public class FileTest13 {
public static void main(String[] args) {
//加true就是追加数据管道,不加就是覆盖数据管道的
try (Writer fileWriter = new FileWriter("day07/src/com/file/test/outWriter.txt",true);) {
// 1、public void write(int c):写一个字符出去
fileWriter.write(65);
fileWriter.write('A');
fileWriter.write('牛');
fileWriter.write("\r\n");
// 2、public void write(string c)写一个字符串出去
fileWriter.write("我是大帅逼");
fileWriter.write("\r\n");
// 3、public void write(String cint pos ,int len):写字符串的一部分出去
fileWriter.write("我是大帅逼知道吗", 0, 5);
fileWriter.write("\r\n");
// 4、public void write(char[] buffer):写一个字符数组出去
char[] chars = {'a', '我', '牛', '比'};
fileWriter.write(chars);
fileWriter.write("\r\n");
// 5、public void write(char[] buffer ,int pos ,int len):写字符数组的一部分出去
fileWriter.write(chars, 1, 3);
fileWriter.write("\r\n");
} catch (Exception e) {
e.printStackTrace();
}
}
}
二. 缓冲流
对原始流进行包装,以提高原始流读写数据的性能
1. 字节缓冲流 BufferedInputStream BufferedOutputStream
原始流:
包装流:
- 原理:字节缓冲输入流自带了8KB缓冲池;字节缓冲输出流也自带了8KB缓冲池
package com.file;
import java.io.*;
public class FileTest14 {
public static void main(String[] args) {
try (InputStream is = new FileInputStream("day07/src/com/file/test/49.jpg");
//1、定义一个字节缓冲输入流包装原始的字节输入流
InputStream bis = new BufferedInputStream(is);
OutputStream os = new FileOutputStream("day07/src/com/file/test/51.jpg");
//2、定义一个字节缓冲输出流包装原始的字节输出流 可以自定义缓冲池大小的
BufferedOutputStream bos = new BufferedOutputStream(os, 8192 * 2);)
{
int read;
byte[] buffer = new byte[1024];
while ((read = bis.read(buffer)) != -1) {
bos.write(buffer, 0, read);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 字符缓冲流
BufferedReader
- 作用:自带8K(8192)的字符缓冲池,可以提高字符输入流读取字符数据的性能。
package com.file;
import java.io.*;
public class FileTest15 {
public static void main(String[] args) {
try (
Reader fr = new FileReader("day07/src/com/file/test/outWriter.txt");
BufferedReader br = new BufferedReader(fr)
) {
// char[] buffer = new char[1024];
// int len;
// while ((len=br.read(buffer))!=-1){
// String s = new String(buffer, 0, len);
// System.out.print(s);
// }
String line;
while ((line = br.readLine()) != null) {
System.out.println(br.readLine());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
BufferedWriter(字符缓冲输出流)
- 作用:自带8K(8192)的字符缓冲池,可以提高字符输出流写字符数据的性能
原始流、缓冲流的性能分析[重点]
当字节数组达到一定程度时就不明显了
3. 转换流
- 如果代码编码和被读取的文本文件的编码是一致的,使用字符流读取文本文件时不会出现乱码!
- 如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码!
字符输入转换流 - 解决不同编码时,字符流读取文本内容乱码的问题。
- 解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了。
package com.file;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
public class FileTest17 {
public static void main(String[] args) {
try (
//1.得到文件的原始字节流
InputStream is = new FileInputStream("day07/src/com/file/test/test.txt");
//2.把原始的字节输入流按照指定的字符集编码转换成字符输入流
InputStreamReader isr = new InputStreamReader(is,"GBK");
//3.把字符输入流包装成缓冲字符输入流
BufferedReader br = new BufferedReader(isr)
) {
String line;
while ((line=br.readLine())!=null){
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
字符输出转换流
控制写出的编码格式
- 作用:可以控制写出去的字符使用什么字符集编码。
- 解决思路:获取字节输出流,再按照指定的字符集编码将其转换成字符输出流,以后写出去的字符就会用该字符集编码了。
package com.file;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class FileTest18 {
public static void main(String[] args) {
try (OutputStream os = new FileOutputStream("day07/src/com/file/test/test.txt",true);
OutputStreamWriter osw = new OutputStreamWriter(os, "GBK");
BufferedWriter bw = new BufferedWriter(osw)
) {
bw.write("我是一只小猪猪");
bw.newLine();
} catch (Exception e) {
e.printStackTrace();
}
}
}
4. 打印流
- 作用:打印流可以实现更方便、更高效的打印数据出去,能实现打印啥出去就是啥出去
package com.file;
import java.io.PrintStream;
public class FileTest19 {
public static void main(String[] args) {
//1.创建一个打印流管道
try (
// PrintStream ps = new PrintStream("day07/src/com/file/test/testPrint.txt",
// Charset.forName("GBK"));
PrintStream ps = new PrintStream("day07/src/com/file/test/testPrint.txt");
) {
ps.println(97);
ps.println('a');
ps.println("我爱你中国abc");
ps.println(true);
ps.println(99.5);
ps.write(97);
} catch (Exception e) {
e.printStackTrace();
}
}
}
两者差别不大,打印功能完全一样的;只是在写数据上一个写字节一个写字符的!使用低级流包装可以append
package com.file;
import java.io.FileOutputStream;
import java.io.PrintWriter;
public class FileTest19 {
public static void main(String[] args) {
//1.创建一个打印流管道
try (
// PrintStream ps = new PrintStream("day07/src/com/file/test/testPrint.txt",
// Charset.forName("GBK"));
PrintWriter ps = new PrintWriter(new FileOutputStream("day07/src/com/file/test/testPrint.txt",true));
) {
ps.println(97);
ps.println('a');
ps.println("我爱你中国abc");
ps.println(true);
ps.println(99.5);
ps.write(97);
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印流的一种应用:输出语句的重定向。
可以把输出语句的打印位置改到某个文件中去。
package com.file;
import java.io.PrintStream;
public class FileTest20 {
public static void main(String[] args) {
try (PrintStream printStream = new PrintStream("day07/src/com/file/test/testPrint.txt");
) {
System.setOut(printStream);
System.out.println("我改变了打印流到文件中去啦!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
5. 数据流
DataOutputstream(数据输出流)
- 允许把数据和其类型一并写出去。
DatalnputStream(数据输入流)
用于读取数据输出流写出去的数据。
package com.file;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileTest21 {
public static void main(String[] args) {
try (
DataOutputStream dos = new DataOutputStream(
new FileOutputStream("day07/src/com/file/test/dos.txt", true));
FileInputStream is = new FileInputStream("day07/src/com/file/test/dos.txt");
DataInputStream dis = new DataInputStream(is)
) {
dos.writeUTF("我是写数据字符串的");
dos.writeByte(97);
dos.writeBoolean(true);
dos.writeDouble(97.4);
dos.writeInt(97);
System.out.println(dis.readUTF());
System.out.println(dis.readByte());
System.out.println(dis.readBoolean());
System.out.println(dis.readDouble());
System.out.println(dis.readInt());
} catch (Exception e) {
e.printStackTrace();
}
}
}
6. 序列化流
- 对象序列化:把Java对象写入到文件中去
- 对象反序列化:把文件里的Java对象读出来
0bjectOutputstream(对象字节输出流)
- 可以把Java对象进行序列化:把Java对象存入到文件中去。
注意:对象如果要参与序列化,必须实现序列化接口(java.io.Serializable)
Objectlnputstream(对象字节输入流)
可以把Java对象进行反序列化:把存储在文件中的Java对象读入到内存中来。
package com.file;
import java.io.*;
public class FileTest22 {
public static void main(String[] args) {
// serializabledObject();
unSerializabledObject();
}
public static void serializabledObject(){
//1.创建一个java对象
User tom = new User("Tom", "123", 12);
//2.创建一个对象字节输出包装原始字节输出流
try (
FileOutputStream fs = new FileOutputStream("day07/src/com/file/test/dos.txt");
ObjectOutputStream oos = new ObjectOutputStream(fs);
) {
oos.writeObject(tom);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void unSerializabledObject(){
try (
FileInputStream fs = new FileInputStream("day07/src/com/file/test/dos.txt");
ObjectInputStream oos = new ObjectInputStream(fs);
) {
User o = (User)oos.readObject();
System.out.println(o);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class User implements Serializable {
private String uname;
//加入transient不参与序列化
private transient String pwd;
private int age;
public User() {
}
public User(String uname, String pwd, int age) {
this.uname = uname;
this.pwd = pwd;
this.age = age;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", pwd='" + pwd + '\'' +
", age=" + age +
'}';
}
}
如果要一次序列化多个对象,咋整?
- 用一个ArrayList集合存储多个对象,然后直接对集合进行序列化即可
- 注意:ArrayList集合已经实现了序列化接口!
7. IO框架
- 解决某类问题,编写的一套类、接口等,可以理解成一个半成品,大多框架都是第三方研发的。
- 好处:在框架的基础上开发,可以得到优秀的软件架构,并能提高开发效率
- 框架的形式:一般是把类、接口等编译成class形式,再压缩成一个,jar结尾的文件发行出去
什么是IO框架
- 封装了java提供的对文件、数据进行操作的代码,对外提供了更简单的方式来对文件进行操作,对数据进行读写等。
Commons-io
Commons-io是apache开源基金组织提供的一组有关10操作的小框架,目的是提高I0流的开发效率。
右键项目 新建Directory,取名为lib等名称,然后右键lib为add to lib即可导入成功啦
package com.file;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FileTest23 {
public static void main(String[] args) throws IOException {
File file = new File("day07/src/com/file/test/49.jpg");
File file1 = new File("day07/src/com/file/test/100.jpg");
FileUtils.copyFile(file,file1);
// java提供的原生
Files.copy(Path.of("day07/src/com/file/test/49.jpg"),Path.of("day07/src/com/file/test/102.jpg"));
String s = Files.readString(Path.of("day07/src/com/file/test/out.txt"));
System.out.println(s);
}
}