qaq
IO流分类
字节流
- 可以操作所有类型的文件
- 读取文件的时候不要有中文
- 每次只能操作一个字节(整数不能超过一个字节)
子类
- InputStream
- OutputStream
字符流
- 只能操作纯文本文件
子类
- Reader
- Writer
字节流
字节输出流
FileOutputStream(File filename, boolean append)
FileOutputStream(String filepath)
字节输入流
FileInputStream fis = new FileInputStream("");
int b;
while((b = fis.read()) != -1) {
System.out.println((char)b);
}
.close(); fis
文件拷贝
小文件
FileInputStream fis = new FileInputStream("");
FileOutputStream fos = new FileOutputStream("");
int b;
while((b = fis.read()) != -1) {
.write(b);
fos}
//释放资源
//先开的最后关闭
.close();
fos.close(); fis
文件大的时候一次次read()太慢
FileInputStream fis = new FileInputStream("");
FileOutputStream fos = new FileOutputStream("");
byte[] buf = new byte[1024 * 1024 * 5];//一般取1024的倍数
while((len = fis.read(buf)) != -1) {
.write(buf, 0, len);
fos}
.close();
fos.close(); fis
字符流
- 字符流 = 字节流 + 字符集
特点
- 输入流:一次读一个字节,遇到中文时,一次读多个字节
- 输出流:底层把数据按照指定的编码方式进行编码,变成字节再写到文件中
使用场景
- 操作纯文本文件
FileReader
public int read()
:读取数据,到末尾返回 -1public int read(char[] buffer)
:读取多个数据,到末尾返回 -1- 细节:按字节进行读取,遇到中文,一次读多个字节,读取后解码,返回一个十进制整数,代表在字符集上的数字
- 字符流的底层也是字节流
FileReader fr = new FileReader("");
int ch;
while((ch = fr.read()) != -1) {
System.out.println((char)ch);
}
.close(); fr
FileReader fr = new FileReader("");
char[] ch = new char[10];
int len;
//read(chars):把读取数据、解码、强转三步合并了,把强转之后的字符放到数组当中
//空参的read + 强制类型转换
while((len = fr.read(ch)) != -1) {
System.out.println(new String(ch, 0, len));
}
.close(); fr
FileWriter
FileWriter fw = new FileWriter("");
.write(25105);//根据字符集的编码方式编码,把编码之后的数据写到文件中
fw.close(); fw
FileWriter fw = new FileWriter("");
char[] ch = {'a', 'b', 'c', '我'};
.write(ch);
fw.close(); fw
字符流底层原理
- 创建字符输入流对象
- 关联文件,并创建缓冲区(长度为8192的字节数组)(字节流无缓冲区)
- 读取数据
- 判断缓冲区中是否有数据
- 缓冲区无数据:从文件中获取数据,装入缓冲区,尽可能装满
- 缓冲区有数据:从缓冲区读取
- 空参read:一次读取一个字节,遇到中文一次读多个字节,把字节解码转成十进制返回
- 有参read:读取字节、解码、强转三步合并,强转后的字符放到数组中
- 判断缓冲区中是否有数据
- 输出数据
- 在内存中创建一个8192的缓冲区,每一次write都会把内容编码写进缓冲区里,出现下面的情况时,会把缓冲区内容写入文件
- 缓冲区满
- 刷新(
flush()
) - 关流(
close()
)
- 在内存中创建一个8192的缓冲区,每一次write都会把内容编码写进缓冲区里,出现下面的情况时,会把缓冲区内容写入文件
缓冲流
加了缓冲区的基本流
字节缓冲流
public BufferedInputStream(InputStream is)
public BufferedOutputStream(OutputStream os)
字符缓冲流
因为字符基本流已经有缓冲区了,所以效率提高不明显
BufferedReader
BufferedWriter
主要体现在两个比较好用的方法
- 输入流:
public String readLine()
:读取一行数据,如果没数据了,返回null。但是不会读取回车换行 - 输出流:
public void newLine()
:跨平台的换行
转换流
是字符流和字节流之间的桥梁
数据源 -> 字节流 -> 转换流 -> 内存 -> 转换流 -> 字节流 ->目的文件
InputStreamReader
OutputStreamWriter
InputStreamReader isr = new InputStreamReader(new FileInputStream(""), "GBK");
int ch;
while((ch = isr.read()) != -1) {
System.out.print((char)ch);
}
.close(); isr
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(""), "GBK");
.write("你好");
osw.close(); osw
JDK11后把FileInputStream
和FileOutputStream
的构造方法加入了字符编码
//将本地文件中的GBK文件,转成UTF-8
InputStreamReader isr = new InputStreamReader(new FileInputStream(""), "GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(""), "UTF-8");
int b;
while((b = isr.read()) != -1) {
.write(b);
osw}
.close();
osw.close(); isr
练习
//用字节流读文件中数据,一次读一行,不能出现乱码
//1.字节流在读中文的时候,会出现乱码,用字符流没事
//2.字节流里面是没有读一行的方法,字符缓冲流可以
//FileInputStream fis = new FileInputStream("");
//InputStreamReader isr = new InputStreamReader(fis);
//BufferedReader br = new BufferedReader(isr);
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("")));
String str;
while((str = br.readLine()) != null) {
System.out.println(str);
}
.close(); br
序列化流
- 是字节流的一种
- 可以把Java中的对象写到本地文件中
- 是高级流
构造方法
public ObjectOutputStream(OutputStream out)
:基本流包装成高级流public final void writeObject(Object obj)
:把对象序列化写出
输出
= new Student("a", 18);
Student stu ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(""));
.writeObject(stu);
oos.close(); oos
注意:要序列化的Javabean类需要实现Serializable接口,Serializable接口是个标记接口
输入
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(""));
//Object o = ois.readObject();
=(Student) ois.readObject();
Student o
System.out.println(o);
.close(); ois
版本号
当一个对象实现了Serializable接口之后,每一次修改这个Javabean类都会生成新的版本号,而每次序列化会把版本号序列化进去,使得在反序列化时可能会出现序列化的对象和当前Javabean类版本号不一致的问题
可以固定版本号
public class Student implements Serializable { private static final long serialVersionUID = 1L;// 唯一格式 建议自动生成 }
transient关键字
- 瞬态关键字
- 被此关键字修饰的变量不会被序列化到本地文件中
private transient String address;
打印流
只有输出流
字节打印流 和 字符打印流
不能操作数据源,只能操作目的地
PrintStream
PrintWriter
字节打印流
字节流底层没缓冲区,自动刷新开不开没区别
构造
public PrintStream(OutputStream/File/String)
:关联字节输出流/文件/文件路径public PrintStream(String fileName, Charset charset)
:指定字符编码public PrintStream(OutputStream out, boolean autoFlush)
:自动刷新public PrintStream(OutputStream out, boolean autoFlush, String encoding)
:指定字符编码
方法
public void write(int b)
:常规方法,和之前一样public void println(Xxx xx)
:特有方法,打印任意数据,自动刷新、换行public void print(Xxx xx)
:特有方法,打印任意数据,不换行public void printf(String format, Object...)
:特有方法,带有占位符的打印语句,不换行
PrintStream ps = new PrintStream(new FileOutputStream(""), true, Charset.forName("GBK"));
.println(97);//写出 + 自动刷新 + 自动换行
ps.print(true);
ps.println();
ps.printf("%s loves %s", "a", "b");
ps.close(); ps
字符打印流
字符流底层有缓冲区,要自动刷新需要手动开启
构造
public PrintWriter(Writer/File/String)
:关联字节输出流/文件/路径public PrintWriter(String fileName, Charset charset)
:指定字符编码public PrintWriter(Write w, boolean autoFlush)
:自动刷新public PrintWriter(OutputStream out, boolean autoFlush, Charset charset)
:指定字符编码且自动刷新
方法
和字节打印流一样
PrintWriter pw = new PrintWriter(new FileWriter(""), true);
.println("abc");
pw.close(); pw
用处
System.out
是一个静态打印流对象,虚拟机启动的时候,由JVM赋值,默认指向控制台
压缩流
- 只能识别.zip文件
- 压缩包里每一个文件在Java中是一个ZipEntry对象
- 解压本质:把每一个ZipEntry对象按照层级拷贝到本地另一个文件夹中
解压缩流
ZipInputStream
未完待续