Java中BufferedOutputStream、BufferedInputStream用法

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

文章目录

介绍

BufferedOutputStream 字节缓冲输出流。顾名思义就是它有一个内部的 buffer(缓存),当写数据时,可以批量的写,提高单字节读写效率。它的工作原理和 BufferedIputStream 一样。与其他流相接,提供特定数据处理功能,是操作其他流的流。

BufferedOutputStream
输出的字节值,暂存在内存数组中,放满后,自动批量输出。放不满,flush()手动刷出
BufferedInputStream
读取一批字节值,暂存在内存数组中,可以一个字节一个字节的处理数组中的数据。这一批处理完,再缓存下一批。

tip:磁盘读取效率低,内存读取效率高

使用

创建对象
1、采用的默认的缓冲区大小,来构造一个字节缓冲输出流对象。内部缓存数组长度8192

BufferedOutputStream out = new BufferedOutputStream(相接的流);
复制代码

2、指定 size 缓冲区大小构造缓冲输出流对象。如下内部缓存数组长度为 16k

BufferedOutputStream out = new BufferedOutputStream(相接的流,16*1024);
复制代码

BufferedOutputStream 方法
1、一次写一个字节。末尾1个字节

write(int b)
复制代码

2、写入全部指定的数组

write(byte[] buff)
复制代码

3、一次写一个字节数组的一部分:从 from 开始的 length 个

write(byte[] buff,int from,int length)
复制代码

4、刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中。

flush()
复制代码

BufferedInputStream 方法
1、读取一个字节

read();
复制代码

2、根据传入的数组长度读取

read(byte[] buff);
复制代码

3、获取剩余的可读取字节量

available();
复制代码

这些方法都是从父类继承的,没有特殊方法

栗子1:写入文件

public class Main {
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("d:/abc/f4");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        //这些数据被写进内存中,并没有写进文件
        bos.write(97);
        bos.write(98);
        bos.write(99);
        //内存大小8192,并没有存满,所以需要手动刷出
        bos.flush();//手动刷出,可以重复执行
        /*
         * close()方法会先执行flush()
         * 然后再执行out.close()
         *
         * 会先刷出缓存
         * 再关闭相接的流
         *
         */
        bos.close();
    }
}
复制代码

运行程序会在 D 盘 abc 文件夹下创建 f4 文件,内容如下:
在这里插入图片描述
使用范围
如果是单字节读取,可以接 buffer。对批量读取,效率并没有帮助。

我们修改上一篇文章 FileInputStream和FileOutputStream用法 的单字节读取。

栗子2:上一章的单字节读取修改

public class Main {
    public static void main(String[] args) {
        System.out.println("请输入文件路径");
        String s = new Scanner(System.in).nextLine();
        File from = new File(s);
        if (!from.isFile()) {
            System.out.println("请输入正确的文件路径");
            return;
        }

        System.out.println("请输入目标文件路径");
        String s2 = new Scanner(System.in).nextLine();
        File to = new File(s2);
        if (to.isDirectory()) {
            System.out.println("不是目录路径,是目标文件路径");
            return;
        }

        try {
            copy(from, to);
            System.out.println("复制成功");
        } catch (Exception e) {
            System.out.println("复制失败");
            e.printStackTrace();
        }
    }

    private static void copy(File from, File to) throws IOException {
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(from));
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(to));
        int b;
        while ((b = in.read()) != -1) {
            out.write(b);
        }
        in.close();
        out.close();
    }
}
复制代码

栗子3:文件拆分/合并

要求:将文件 d:/abc/a.jpg 拆分,拆分后的文件保存到 d:/abc/a.jpg_aplit 文件夹中
拆分后的文件名称为a.jpg.1、a.jpg.2、a.jpg.3…

public class Main {
    public static void main(String[] args) {
        System.out.println("原文件路径");
        String s = new Scanner(System.in).nextLine();
        File file = new File(s);
        if (!file.isFile()) {
            System.out.println("请输入正确的文件路径");
            return;
        }
        System.out.println("拆分文件大小(kb)");
        long size = new Scanner(System.in).nextLong();
        size *= 1024;
        try {
            split(file, size);
            System.out.println("拆分完成");
        } catch (Exception e) {
            System.out.println("拆分失败");
            e.printStackTrace();
        }
    }

    private static void split(File file, long size) throws Exception {
        //原文件名
        String name = file.getName();
        //准备拆分文件存放目录
        File dir = new File(file.getAbsolutePath() + "_split");
        if (dir.exists()) {
            //存在,清空
            File[] files = dir.listFiles();
            for (File file2 : files) {
                file2.delete();
            }
        } else {
            //不存在,新建
            dir.mkdirs();
        }

        //字节计数变量  和  文件计数变量
        long byteCount = 0;
        int fileCount = 0;
        FileInputStream in = new FileInputStream(file);
        FileOutputStream out = null;

        int b;
        while ((b = in.read()) != -1) {
            //如果没有输出流
            //或者前一个文件满了
            //创建新的输出流
            if (out == null || byteCount == size) {
                //如果前面文件满了,要先关闭前一个流
                if (out != null) {
                    out.close();
                }
                out = new FileOutputStream(new File(dir, name + "." + (++fileCount)));
                byteCount = 0;
            }
            out.write(b);
            byteCount++;
        }
        in.close();
        out.close();
    }
}
复制代码

现有一个88k的图片
这里写图片描述
运行程序:

原文件路径
d:/abc/headimg.jpg
拆分文件大小(kb)
22
拆分完成
复制代码

这里写图片描述
这里写图片描述

上面的程序是单字节读取,我们改用 BufferedOutputStream 和 BufferedInputStream 来增加效率:

private static void split(File file, long size) throws Exception {
        //原文件名
        String name = file.getName();
        //准备拆分文件存放目录
        File dir = new File(file.getAbsolutePath() + "_split");
        if (dir.exists()) {
            //存在,清空
            File[] files = dir.listFiles();
            for (File file2 : files) {
                file2.delete();
            }
        } else {
            //不存在,新建
            dir.mkdirs();
        }

        //字节计数变量  和  文件计数变量
        long byteCount = 0;
        int fileCount = 0;

        BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
        BufferedOutputStream out = null;

        int b;
        while ((b = in.read()) != -1) {
            //如果没有输出流
            //或者前一个文件满了
            //创建新的输出流
            if (out == null || byteCount == size) {
                //如果前面文件满了,要先关闭前一个流
                if (out != null) {
                    out.close();
                }
                out = new BufferedOutputStream(new FileOutputStream(new File(dir, name + "." + (++fileCount))));
                byteCount = 0;
            }
            out.write(b);
            byteCount++;
        }
        in.close();
        out.close();
    }
复制代码

栗子4:文件合并

public class Main {
    public static void main(String[] args) {
        System.out.println("输入拆分文件存放的文件夹路径");
        String s = new Scanner(System.in).nextLine();
        File dir = new File(s);
        if (!dir.isDirectory()) {
            System.out.println("请输入正确的文件夹路径");
            return;
        }

        System.out.println("输入合并的目标文件名");
        String s2 = new Scanner(System.in).nextLine();
        File name = new File(s2);
        if (name.isDirectory()) {
            System.out.println("请输入具体的文件路径,不是目录路径");
            return;
        }

        try {
            conbine(dir, name);
            System.out.println("合并完成");
        } catch (Exception e) {
            System.out.println("合并失败");
            e.printStackTrace();
        }
    }

    private static void conbine(File dir, File name) throws Exception {
        File[] list = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File f) {
                //只列出数字后缀的文件
                if (f.isDirectory()) {
                    return false;
                }

                String n = f.getName();
                int index = n.lastIndexOf(".");
                if (index == -1) {
                    return false;
                }
                n = n.substring(index + 1);
                return n.matches("\\d+");
            }
        });

        //外接比较器,对文件按数字大小排序
        Arrays.sort(list, new Comparator<File>() {
            @Override
            public int compare(File f1, File f2) {
                String n1 = f1.getName();
                String n2 = f2.getName();

                n1 = n1.substring(n1.lastIndexOf(".") + 1);
                n2 = n2.substring(n2.lastIndexOf(".") + 1);

                int a = Integer.parseInt(n1);
                int b = Integer.parseInt(n2);
                return a - b;
            }
        });

        FileOutputStream out = new FileOutputStream(name);
        FileInputStream in = null;
        byte[] buff = new byte[8192];
        int n;
        for (File f : list) {
            in = new FileInputStream(f);
            while ((n = in.read(buff)) != -1) {
                out.write(buff, 0, n);
            }
            in.close();
        }
        out.close();
    }
}
复制代码

输出结果

输入拆分文件存放的文件夹路径
d:/abc/headimg.jpg_split
输入合并的目标文件名
d:/abc/copy.jpg
合并完成
复制代码

猜你喜欢

转载自juejin.im/post/7016979790590640158