iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 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://www.lsjlt.com/news/137858.html(转载时请注明来源链接)

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

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 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中Thread类详解及常用的方法
    目录一、Thread 的常见构造方法二、Thread 的常见属性三、创建线程四、中断线程五、线程等待六、获取线程引用七、线程休眠八、线程状态总结一、Thread 的常见构造方法 方法...
    99+
    2024-04-02
  • java的内部类和外部类用法讲解
    目录一、为何使用内部类二、内部类与外部类的联系2.1内部类是一个相对独立的实体,与外部类不是is-a关系2.2内部类可以直接访问外部类的元素,但是外部类不可以直接访问内部类的元素2....
    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中Math类常用方法代码详解
    近期用到四舍五入想到以前整理了一点,就顺便重新整理好经常见到的一些四舍五入,后续遇到常用也会直接在这篇文章更新。。。public class Demo{ public static void main(String args[]){ ...
    99+
    2023-05-31
    java math 方法
  • Java中String类常用方法总结详解
    目录一. String对象的比较1. ==比较是否引用同一个对象2. boolean equals(Object anObject)3. int compareTo(String s...
    99+
    2024-04-02
  • 详解Java String类常用方法有哪些
    一、构造器 实质是给底层的char数组value赋值 String s1 = new String(); String s2 = new String(“abc”); Strin...
    99+
    2024-04-02
  • 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
  • Java中String类的常用方法总结
    目录概述特点使用步骤常用方法判断功能的方法获取功能的方法转换功能的方法分割功能的方法概述 java.lang.String 类代表字符串。Java程序中所有的字符串文字(例如&quo...
    99+
    2022-11-13
    Java String类常用方法 Java String类 方法 Java String类
  • Python类方法总结讲解
    一、类方法 在类中的函数称为类方法。与普通函数定义稍有区别。 1.普通方法 1.1 普通方法定义 普通方法与一般函数的定义稍有区别的点在于第一个参数是self,,指代的意思是指向...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作