返回顶部
首页 > 资讯 > 后端开发 > Python >Java BufferedOutputStream类的常用方法讲解
  • 434
分享到

Java BufferedOutputStream类的常用方法讲解

2024-04-02 19:04:59 434人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录BufferedOutputStream类的常用方法构造方式常用方法程序示例BufferedOutputStream深入分析代码准备原因分析手动刷盘buffer源码分析关于buf

BufferedOutputStream类的常用方法

BufferedOutputStream字节缓冲输出流

构造方式

第一种开发


public BufferedOutputStream(OutputStream out)

采用的默认的缓冲区大小(足够大了) ,来构造一个字节缓冲输出流对象


public BufferedOutputStream(OutputStream out,int size)

指定size缓冲区大小构造缓冲输出流对象

IllegalArgumentException - 如果 size <= 0

常用方法


public void write(int b)throws IOException

一次写一个字节

  • b - 要写入的字节。

public void write(byte[] b,int off,int len) throws IOException

一次写一个字节数组的一部分

  • b - 数据。
  • off - 数据的起始偏移量。
  • len - 要写入的字节数。

public void flush() throws IOException

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


public void close() throws IOException

关闭此输出流并释放与此流有关的所有系统资源。

FilterOutputStream 的 close 方法先调用其 flush 方法,然后调用其基础输出流的 close 方法。

程序示例


public static void main(String[] args) throws Exception {    
    //符合Java一种设计模式:装饰者设计模式(过滤器:Filter)
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")) ;        
    //写数据
    bos.write("hello".getBytes());
    //释放资源
    bos.close();
}

BufferedOutputStream深入分析

FileOutputStream和BufferedOutputStream都提供了一系列的将数据写入文件的方式,并且我们都知道BufferedOutputStream要比直接使用FileOutputStream写入速度要快,本文通过案例实际演示一下两者的区别。

代码准备


public class BufferFile {
    public static void main(String[] args) {
        //每次向文件中写入一个8字节的数组
        byte[] bytes = "1234567\n".getBytes();
        //每隔100毫秒通过buffer的方式向文件中写入数据
        new Thread(() -> {
            System.out.println("buffer_while start...");
            File file = new File("/var/file_test_data/out_buffer_while.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                while (true) {
                    Thread.sleep(100);
                    bufferedOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        //通过buffer的方式向文件中写入1千万次
        new Thread(() -> {
            System.out.println("buffer_for start...");
            File file = new File("/var/file_test_data/out_buffer_for.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                for (int i = 0; i < 10000000; i++) {
                    bufferedOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(new Date() + ": buffer_for end...");
        }).start();
        //通过file的方式向文件中写入1千万次
        new Thread(() -> {
            System.out.println("file_for start...");
            File file = new File("/var/file_test_data/out_file_for.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                for (int i = 0; i < 10000000; i++) {
                    fileOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(new Date() + ": file_for end...");
        }).start();
    }
}

开始运行

在这里插入图片描述

强行停止后的运行结果

在这里插入图片描述

1、file和buffe写入速度比较

两者分别写入1千万次,时间上buffer比file快8秒,如果当写入次数指数级增加时,buffer的优势将更加明显。

2、数据写入完整性问题

buffer虽然要比file快,但是从最终数据上可以看出,buffer会丢数据

  • 当第一个线程写入时数据还未满8kb时,强制停止java进程,最终out_buffer_while.txt没有数据。
  • 第二个线程,虽然最终代码执行完毕,但是比较file方式,out_buffer_for.txt文件看起来也丢了一部分数据。

原因分析

当使用buffer读写文件时,数据并没有直接被写入磁盘,而是被缓存到一个字节数据中,这个字节数组的大小是8kb,默认情况下只有当8kb被填充满了以后,数据才会被一次性写入磁盘,这样一来就大大减少了系统调用的次数(file是每一次write都会产生系统调用),当然也正是因为buffer中的每一次write只是写入到内存中(JVM自身内存中),所以当数据未写入磁盘前,如果JVM进程挂了,那么就会造成数据丢失。

手动刷盘

为了解决数据丢失的问题,buf中提供了flush()方法,用户可以自行决定合适将数据刷写到磁盘中

  • 如果你的flush()调用的非常频繁,那就会退化为普通的file模式了。
  • 如果你的flush()调用的又不太频繁,那么丢数据的可能性就比较高。
  • 无论如何业务逻辑中数据写完时,一定要调用一次flush(),确保缓冲区的数据刷到磁盘上。

将无限循环写入的代码注释掉,在buf写1千万完成后,加上bufferedOutputStream.flush();


public class BufferFile {
    public static void main(String[] args) {
        //每次向文件中写入一个8字节的数组
        byte[] bytes = "1234567\n".getBytes();
        //每隔100毫秒通过buffer的方式向文件中写入数据
        
        //通过buffer的方式向文件中写入1千万次
        new Thread(() -> {
            System.out.println("buffer_for start...");
            File file = new File("/var/file_test_data/out_buffer_for.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                for (int i = 0; i < 10000000; i++) {
                    bufferedOutputStream.write(bytes);
                }
                bufferedOutputStream.flush();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(new Date() + ": buffer_for end...");
        }).start();
        //通过file的方式向文件中写入1千万次
        new Thread(() -> {
            System.out.println("file_for start...");
            File file = new File("/var/file_test_data/out_file_for.txt");
            FileOutputStream fileOutputStream;
            try {
                fileOutputStream = new FileOutputStream(file);
                for (int i = 0; i < 10000000; i++) {
                    fileOutputStream.write(bytes);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(new Date() + ": file_for end...");
        }).start();
    }
}

这次再看数据写入完整了

在这里插入图片描述

buffer源码分析

类的机构图

在这里插入图片描述

首先当创建一个BufferedOutputStream对象时,构造方法就初始化了缓冲的字节数组大小为8kb


	protected byte buf[];
    public BufferedOutputStream(OutputStream out) {
        this(out, 8192);
    }
    public BufferedOutputStream(OutputStream out, int size) {
        super(out);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }

当调用buffer.write(b)时,调用的是父类FilterOutputStream的方法


    public void write(byte b[]) throws IOException {
    	//写入的字节数组b,从0开始,一共要写入的长度
        write(b, 0, b.length);
    }
    	
    public void write(byte b[], int off, int len) throws IOException {
        if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
            throw new IndexOutOfBoundsException();
		//遍历数组,一个字节一个字节的把数据写入数组中
        for (int i = 0 ; i < len ; i++) {
            write(b[off + i]);
        }
    }
    
    public synchronized void write(int b) throws IOException {
    	//判断字节长度是否超过buf.length,buf在初始化已经指定大小为8192,即8kb
    	//如果超过则调用flushBuffer
        if (count >= buf.length) {
            flushBuffer();
        }
        把每一个字节写入缓冲的buf数组中,并且统计值count++
        buf[count++] = (byte)b;
    }
    private void flushBuffer() throws IOException {
        if (count > 0) {
        	//真正的调用OutputStream,写入数据到磁盘中
        	//写入buf缓冲字节数组数据,从0下标开始,一直写到count,即有多少写多少。
            out.write(buf, 0, count);
            count = 0;
        }
    }

关于buf缓冲数据大小设置

buffer提供了可以自定义缓冲大小的构造方法


    public BufferedOutputStream(OutputStream out, int size) {
        super(out);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }

如果缓冲大小设置的比较大。

  • 好处:进一步减少调用系统内核写数据的方法,提高写入速度,kafka的批写入默认就是16kb写一次。
  • 坏处:1、丢失的数据可能会更多,2、要注意堆内存的消耗。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: Java BufferedOutputStream类的常用方法讲解

本文链接: https://lsjlt.com/news/137858.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java BufferedOutputStream类的常用方法讲解
    目录BufferedOutputStream类的常用方法构造方式常用方法程序示例BufferedOutputStream深入分析代码准备原因分析手动刷盘buffer源码分析关于buf...
    99+
    2024-04-02
  • Java BeanUtils工具类常用方法讲解
    谨慎使用这个copyproperties这个功能,相同的属性都会被替换,不管是否有值  BeanUtils 是 Apache commons组件的成员之一,主要用于简化J...
    99+
    2024-04-02
  • Java深入讲解Object类常用方法的使用
    目录1.Object类的常用方法2.equals()方法3.toString方法4.getClass方法5.对象运算符instanceof实例Java代码java继承 1.Objec...
    99+
    2024-04-02
  • Java深入浅出讲解String类常见方法
    目录1.定义字符串2.字符串的存储3.String中常用的方法3.1字符串的比较3.2查找字符串3.3转换字符串4.StringBuilder和StringBuffer5.常量池1....
    99+
    2024-04-02
  • Java详细讲解Math和Random类中有哪些常用方法
    java.lang.Math当中提供了一系列的静态方法用于科学计算;其方法的参数和返回值的类型一般为double型。 下来我就简单的介绍一下Math类中常用的方法。 public s...
    99+
    2024-04-02
  • java中Vector类的常用方法详解
    目录publicvoidadd(intindex, Eelement)publicbooleanaddAll(intindex, Collection<ex...
    99+
    2024-04-02
  • Java之常用类小结案例讲解
    Java常用类 包装类 由于Java语言中的基本类型不是面向对象,并不具备对象的性质,实际使用存在很多不便。Java在java.lang包中提供了八种基本类型对应的包装类,可以方便地...
    99+
    2024-04-02
  • java的内部类和外部类用法讲解
    目录一、为何使用内部类二、内部类与外部类的联系2.1内部类是一个相对独立的实体,与外部类不是is-a关系2.2内部类可以直接访问外部类的元素,但是外部类不可以直接访问内部类的元素2....
    99+
    2024-04-02
  • Java中Thread类详解及常用的方法
    目录一、Thread 的常见构造方法二、Thread 的常见属性三、创建线程四、中断线程五、线程等待六、获取线程引用七、线程休眠八、线程状态总结一、Thread 的常见构造方法 方法...
    99+
    2024-04-02
  • Java超详细讲解类变量和类方法
    目录1.static静态变量2.类变量(静态变量的访问)3.类方法1.static静态变量 1.静态变量被同一个类的所有对象共享 2.static类变量在类加载的时候就生成使用 st...
    99+
    2024-04-02
  • Java中String类常用方法使用详解
    目录一、length()二、equals三、charAt()四、indexOf()五、trim()六、compareTo()七、toLowerCase()八、toUpper...
    99+
    2022-11-13
    Java String类 常用方法 Java String类 方法 Java String类
  • Java异常 Exception类及其子类(实例讲解)
    C语言时用if...else...来控制异常,Java语言所有的异常都可以用一个类来表示,不同类型的异常对应不同的子类异常,每个异常都对应一个异常类的对象。Java异常处理通过5个关键字try、catch、finally、throw、thr...
    99+
    2023-05-30
    java exception 子类
  • 详解Java String类常用方法有哪些
    一、构造器 实质是给底层的char数组value赋值 String s1 = new String(); String s2 = new String(“abc”); Strin...
    99+
    2024-04-02
  • Java中String类常用方法总结详解
    目录一. String对象的比较1. ==比较是否引用同一个对象2. boolean equals(Object anObject)3. int compareTo(String s...
    99+
    2024-04-02
  • Java中Math类常用方法代码详解
    近期用到四舍五入想到以前整理了一点,就顺便重新整理好经常见到的一些四舍五入,后续遇到常用也会直接在这篇文章更新。。。public class Demo{ public static void main(String args[]){ ...
    99+
    2023-05-31
    java math 方法
  • Java File类的概述及常用方法使用详解
    目录一、File类的概述和构造方法二、File类创建功能三、File类创建和获取功能四、File类的删除功能一、File类的概述和构造方法 public class File ext...
    99+
    2024-04-02
  • Java 详细讲解线程的状态及部分常用方法
    可以通过 Thread.getState 方法获得线程的状态(线程一共有 6 种状态) NEW(新建)new:尚未启动 RUNNABLE(可运行状态)runnable:正在 JVM ...
    99+
    2024-04-02
  • Java-String类常用方法汇总
    1.获取字符串长度 int length(); 2.获取指定位置上某个字符 char charAt(int index); 3.获取指定字符在字符串中位置 int indexOf(int ch);//...
    99+
    2023-09-08
    idea java
  • Python类方法总结讲解
    一、类方法 在类中的函数称为类方法。与普通函数定义稍有区别。 1.普通方法 1.1 普通方法定义 普通方法与一般函数的定义稍有区别的点在于第一个参数是self,,指代的意思是指向...
    99+
    2024-04-02
  • java中Enum类的常用方法实现
    枚举类型预定义的方法:public static enumtype[] values() //枚举类型的数组,该数组包含枚举的所有枚举成员,并按他们的生命顺序存储 public static enumtype valueOf(...
    99+
    2017-07-03
    java入门 java Enum
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作