11 Java文件处理之写入、读取:IO流(中):高级流(缓冲流、转换流、序列化流和反序列化流、打印流)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

前面学FileReader和FileWriter字符流:对于中文只能处理当前平台的编码方式进行编码和解码,不能指定编码格式进行编码解码。

这个指定编码的功能,在本节的高级流(转换流)上就会得到处理。

另外,高级流都是在上节的四中基本流上面进一步封装而来的,可以说前面基本流是他们的爸爸。

缓冲流(提供缓冲区,加快读取写入速度,减少和硬盘交互次数)
转换流(可以指定编码格式)

基本流—>缓冲流
转换流(都是字符流)
序列化流和反序列化流(都是字节流)
打印流(不能读,只能写,只有输出流)

在这里插入图片描述

在这里插入图片描述

一、缓冲流

在这里插入图片描述
缓冲流就是在之前基本流的基础上加了一个缓冲区(缓冲数组,减少和磁盘交互的次数),可以加快读写的效率。
其实基本流中的字符流本身底层原理就是有缓冲区的参考博客,所以缓冲流的对于字符流的加快读写效率并没有快很多。主要是其中有几个非常好用的方法需要我们学习一下。

1 字节缓冲流

  • 原理:底层自带了长度为8192的缓冲区(缓冲数组)提高性能
    这样每次和硬盘交互我都可以直接将8192个字节放进内存,就是是一个字节一个字节的读8193个字节才和硬盘交互一次,不然一个字节就和硬盘交互一次太浪费时间了。

(1)BufferedInputStream:字节缓冲输入流

【注】:其实基本流学好了,这个没有什么区别。

构造方法
---- BufferedInputStream(InputStream in):创建一个使用默认缓冲区大小的缓冲输入流。

默认缓冲区是 8192 的字节数组

---- BufferedInputStream(InputStream in, int size):创建一个指定缓冲区大小的缓冲输入流。
输入方法
---- int read(): 读取一个字节的数据。

返回值是读取的字节(0 到 255 之间的整数),如果已经到达流的末尾,返回 -1
如果是处理文本文件通常要结合char强转使用。

---- int read(byte[] b) : 读取多个字节的数据。

一次读取多个字节(返回值表示本次读取到的字节的个数,不是值),从文件中读取字节并将其存储到字节数组 b 中(每次读取会尽可能把数组装满),返回读取的字节数,如果到达文件末尾返回 -1。
如果是处理文本文件通常结合String(字节数组,start,end)构造方法来使用,start、end分别是字节数组起始索引

---- int read(byte[] b, int off, int len) : 读取多个字节的数据。

从输入流中读取最多 len 个字节的数据,并将其存储到字节数组 b 的从 off 位置开始的部分,返回实际读取的字节数,或者在流结束时返回 -1。

关闭资源 void close()

关闭缓冲流就行,在底层关闭缓冲流里面已经封装了关闭基本流的代码。所以关闭缓冲流就直接将基本流一起关闭了。

代码演示
---- 读取文件(一个一个字节读):int read()

int read()

public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // a.txt文件内容:abcdefdghiuihhj
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(".\\a.txt"));
        StringBuilder sb = new StringBuilder();
        int b;
        while((b = bis.read()) != -1){
   
            sb.append((char)b);
        }
        bis.close();  // 关闭流,关闭缓冲流,基本流也会关闭
        System.out.println(sb.toString());   // abcdefdghiuihhj
    }

}
---- 读取文件(多个多个字节读):int read(byte[] b)

int read(byte[] b)

public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // a.txt文件内容:abcdefdghiuihhj
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(".\\a.txt"));
        try(bis){
   
            StringBuilder sb = new StringBuilder();
            byte[] bytes = new byte[2];
            int len;
            while ((len = bis.read(bytes)) != -1) {
   
                sb.append(new String(bytes, 0, len));
            }
            System.out.println(sb.toString());   // abcdefdghiuihhj
        }
    }
}

(2)BufferedOutputStream:字节缓冲输出流

构造方法

【注】:覆盖模式还是追加模式还是在基本流的构造方法里面传入就可以了

---- BufferedOutputStream(OutputStream out):使用默认的缓冲区大小创建一个新的缓冲输出流,out 是底层的输出流(例如 FileOutputStream)
---- BufferedOutputStream(OutputStream out, int size):创建一个带有指定缓冲区大小的缓冲输出流,size 指定缓冲区的大小
写入方法
---- void write(int b):一个一个字节写入

将指定的字节写入到缓冲区。如果缓冲区满了,则会将缓冲区中的内容写入到底层输出流。

---- void write(byte[] b):多个多个字节写入
---- void write(byte[] b, int off, int len):多个多个字节写入

将 b 数组中从 off 位置开始的 len 个字节写入到缓冲区中。如果缓冲区满了,也会将缓冲区的内容写入到底层输出流。

关闭资源 void close()

关闭缓冲流就行,在底层关闭缓冲流里面已经封装了关闭基本流的代码。所以关闭缓冲流就直接将基本流一起关闭了。

代码演示
---- 写入文件(单个单个字节写入void write(int b)):覆盖模式

void write(int b)

public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // a.txt文件  写入 abc
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
        try (bos) {
   
            bos.write(97);
            bos.write(98);
            bos.write(99);
        }
    }
}
---- 写入文件(多个多个字节写入void write(byte[] b)):覆盖模式

void write(byte[] b)

public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // a.txt文件  写入 abc你好
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
        try (bos) {
   
            bos.write("abc你好".getBytes());  // 默认是平台的utf-8编码写入字节,也可以指定编码写入
        }
    }
}

在这里插入图片描述

---- 写入文件(多个多个字节写入void write(byte[] b)):追加模式
public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // a.txt文件内容:abc你好  追加写入 \n曹潇潇我爱你
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt", true));
        try (bos) {
   
            bos.write("\n曹潇潇我爱你".getBytes());
        }
    }
}

在这里插入图片描述

(3)字节缓冲流拷贝文件

同样是拷贝视频文件

public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // 拷贝 D:\GraduateStudent\研一\taobao_项目\【深度学习理论基础】\13-13 - 2.6更多导数示例.mp4 到 IDEA当前工作路径 video.mp4
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\GraduateStudent\\研一\\taobao_项目\\【深度学习理论基础】\\13-13 - 2.6更多导数示例.mp4"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(".\\video.mp4"));
        try(bis; bos) {
   
            byte[] bytes = new byte[1024*1024*5];
            int len;
            while ((len = bis.read(bytes)) != -1) {
   
                bos.write(bytes, 0, len);
            }
        }
    }
}

(4)字节缓冲流底层原理

参考视频

2 字符缓冲流

(1)BufferedReader:字符缓冲输入流

构造方法
---- BufferedReader(Reader in):创建一个使用默认大小(8192长度的字符数组)输入缓冲区的缓冲字符输入流
---- BufferedReader(Reader in, int size):创建一个使用指定大小输入缓冲区的缓冲字符输入流
读取方法
---- int read():一个一个字符的读

读取一个字符。返回值是读取的字符的对应字符集对应的十进制数字(作为 int 返回),如果已经到达流的末尾,返回 -1。

---- int read(char[] cbuf):多个多个字符的读,返回实际读取的字符数
---- int read(char[] cbuf, int off, int len):多个多个字符的读,返回实际读取的字符数

从字符输入流中最多读取 len 个字符,存储到 cbuf 数组中,从 off 位置开始。返回实际读取的字符数,流结束时返回 -1。

---- String readLine():一行一行的读

读取一行文本。当到达流末尾时,返回 null。通常用于逐行读取文件内容。
【注】:虽然是一行一行读。但是并不会将换行符也读到内存,也就是说每行结尾的换行符不会读进内存。

关闭资源:void close()
代码演示
---- 读取文件(一个一个字符的读):int read()
public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // 读取 a.txt 里面内容为: abc你好\r\n曹潇潇我爱你
        BufferedReader br = new BufferedReader(new FileReader(".\\a.txt"));
        StringBuilder sb = new StringBuilder();
        int ch;
        while ((ch = br.read()) != -1) {
   
            sb.append((char) ch);
        }
        br.close();
        System.out.println(sb.toString());
        /*
        abc你好
        曹潇潇我爱你
        */
    }
}
---- 读取文件(多个多个字符的读):int read(char[] cbuf)
public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // 读取 a.txt 里面内容为: abc你好\r\n曹潇潇我爱你
        BufferedReader br = new BufferedReader(new FileReader(".\\a.txt"));
        try(br){
   
            StringBuilder sb = new StringBuilder();
            char[] buf = new char[2];
            int len;
            while ((len = br.read(buf)) != -1) {
   
                sb.append(new String(buf, 0, len));
            }
            System.out.println(sb.toString());
        }
        /*
        abc你好
        曹潇潇我爱你
        */
    }
}
---- 读取文件(一行一行的读):String readLine()
public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // 读取 a.txt 里面内容为: abc你好\r\n曹潇潇我爱你
        BufferedReader br = new BufferedReader(new FileReader(".\\a.txt"));
        try(br){
   
            String line;
            while ((line = br.readLine()) != null) {
   
                System.out.println(line);
            }
        }
        /*
        abc你好
        曹潇潇我爱你
        */
    }
}

通常我们喜欢将每一行的String放进一个List再进行进一步的处理加工

public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // 读取 a.txt 里面内容为: abc你好\r\n曹潇潇我爱你
        BufferedReader br = new BufferedReader(new FileReader(".\\a.txt"));
        ArrayList<String> list = new ArrayList<>();
        try(br){
   
            String line;
            while ((line = br.readLine()) != null) {
   
                list.add(line);
            }
        }
        System.out.println(list);  // [abc你好, 曹潇潇我爱你]
    }
}
---- 读取文件:指定编码格式
public class Test {
   
    public static void main(String[] args) throws IOException {
   
        BufferedReader br = new BufferedReader(new FileReader(".\\gbk.txt",Charset.forName("GBK")));
        StringBuilder sb = new StringBuilder();
        try(br){
   
            String line;
            while ((line = br.readLine()) != null) {
   
                sb.append(line).append("\n");
            }
        }
        System.out.println(sb.toString());
    }
}

(2)BufferedWriter: 字符缓冲输出流

构造方法
---- BufferedWriter(Writer out):使用默认缓冲区大小(8192字符数字)创建一个缓冲字符输出流
---- BufferedWriter(Writer out, int size):创建一个具有指定缓冲区大小的缓冲字符输出流
写入方法
---- void write(int c):一个一个写入,将指定的字符写入到缓冲区。
---- void write(char[] cbuf):多个多个写入
---- void write(char[] cbuf, int off, int len):多个多个写入

将字符数组的 len 个字符,从偏移量 off 开始,写入到缓冲区。

----- void write(String s):直接写入字符串
----- void write(String s, int off, int len):直接写入字符串

将字符串的 len 个字符,从偏移量 off 开始,写入到缓冲区。

----- void newLine():写入一个跨平台换行符

写入一个行分隔符。BufferedWriter 会根据操作系统自动使用适当的换行符,例如 Windows 使用 \r\n,Unix 使用 \n。
原因是,不可能每换个平台我们都去修改源码,我们调用这个方法写入就可以解决这个问题了。

关闭资源:void close()
代码演示
---- 写入文件(一个一个字符写入void write(int c) (超笨)):覆盖写入
public class Test {
   
    public static void main(String[] args) throws IOException {
   
        // 往a.txt中覆盖写入 abc我   a -> 97  b -> 98  c -> 99  我 -> 25105
        BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
        try(bw) {
   
            bw.write(97);
            bw.write(98);
            bw.write(99);
            bw.write(25105);
        }
    }
}

在这里插入图片描述

---- 写入文件(多个多个字符写入void w
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值