首页 > 其他分享 >缓冲流

缓冲流

时间:2024-08-01 09:54:57浏览次数:14  
标签:字节 缓冲 写入 bw 缓冲区 new

Java 的缓冲流是对字节流和字符流的一种封装,通过在内存中开辟缓冲区来提高 I/O 操作的效率。Java 通过 BufferedInputStream 和 BufferedOutputStream 来实现字节流的缓冲,通过 BufferedReader 和 BufferedWriter 来实现字符流的缓冲。

缓冲流的工作原理是将数据先写入缓冲区中,当缓冲区满时再一次性写入文件或输出流,或者当缓冲区为空时一次性从文件或输入流中读取一定量的数据。这样可以减少系统的 I/O 操作次数,提高系统的 I/O 效率,从而提高程序的运行效率。

字节缓冲流


构造方法

  • BufferedInputStream(InputStream in) :创建一个新的缓冲输入流,注意参数类型为InputStream
  • BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流,注意参数类型为OutputStream
// 创建字节缓冲输入流,先声明字节流
FileInputStream fps = new FileInputStream(b.txt);
BufferedInputStream bis = new BufferedInputStream(fps)

// 创建字节缓冲输入流(一步到位)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("b.txt"));

// 创建字节缓冲输出流(一步到位)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));

字节缓冲流为什么快

传统的 Java IO 是阻塞模式的,它的工作状态就是“读/写,等待,读/写,等待。。。。。。”

字节缓冲流解决的就是这个问题:一次多读点多写点,减少读写的频率,用空间换时间

  • 减少系统调用次数:在使用字节缓冲流时,数据不是立即写入磁盘或输出流,而是先写入缓冲区,当缓冲区满时再一次性写入磁盘或输出流。这样可以减少系统调用的次数,从而提高 I/O 操作的效率。
  • 减少磁盘读写次数:在使用字节缓冲流时,当需要读取数据时,缓冲流会先从缓冲区中读取数据,如果缓冲区中没有足够的数据,则会一次性从磁盘或输入流中读取一定量的数据。同样地,当需要写入数据时,缓冲流会先将数据写入缓冲区,如果缓冲区满了,则会一次性将缓冲区中的数据写入磁盘或输出流。这样可以减少磁盘读写的次数,从而提高 I/O 操作的效率。
  • 提高数据传输效率:在使用字节缓冲流时,由于数据是以块的形式进行传输,因此可以减少数据传输的次数,从而提高数据传输的效率。

BufferedInputStream 的 read 方法:

public synchronized int read() throws IOException {
    if (pos >= count) {     // 如果当前位置已经到达缓冲区末尾
        fill();             // 填充缓冲区
        if (pos >= count)   // 如果填充后仍然到达缓冲区末尾,说明已经读取完毕
            return -1;      // 返回 -1 表示已经读取完毕
    }
    return getBufIfOpen()[pos++] & 0xff; // 返回当前位置的字节,并将位置加 1
}

这段代码主要有两部分:

  • fill():该方法会将缓冲 buf 填满。
  • getBufIfOpen()[pos++] & 0xff:返回当前读取位置 pos 处的字节(getBufIfOpen()返回的是 buffer 数组,是 byte 类型),并将其与 0xff 进行位与运算。这里的目的是将读取到的字节 b 当做无符号的字节处理,因为 Java 的 byte 类型是有符号的,而将 b 与 0xff 进行位与运算,就可以将其转换为无符号的字节,其范围为 0 到 255。

FileInputStream 的 read 方法:

public int read() throws IOException {
    return read0();
}
    
private native int read0() throws IOException;

BufferedOutputStream 的 write(byte b[], int off, int len) 方法:

public synchronized void write(byte b[], int off, int len) throws IOException {
    if (len >= buf.length) {    // 如果写入的字节数大于等于缓冲区长度
        /* 如果请求的长度超过了输出缓冲区的大小,
           先刷新缓冲区,然后直接将数据写入。
           这样可以避免缓冲流级联时的问题。*/
        flushBuffer();          // 先刷新缓冲区
        out.write(b, off, len); // 直接将数据写入输出流
        return;
    }
    if (len > buf.length - count) { // 如果写入的字节数大于空余空间
        flushBuffer();              // 先刷新缓冲区
    }
    System.arraycopy(b, off, buf, count, len); // 将数据拷贝到缓冲区中
    count += len;                             // 更新计数器
}

首先,该方法会检查写入的字节数是否大于等于缓冲区长度,如果是,则先将缓冲区中的数据刷新到磁盘中,然后直接将数据写入输出流。这样做是为了避免缓冲流级联时的问题,即缓冲区的大小不足以容纳写入的数据时,可能会引发级联刷新,导致效率降低。

级联问题(Cascade Problem)是指在一组缓冲流(Buffered Stream)中,由于缓冲区的大小不足以容纳要写入的数据,导致数据被分割成多个部分,并分别写入到不同的缓冲区中,最终需要逐个刷新缓冲区,从而导致性能下降的问题。

其次,如果写入的字节数小于缓冲区长度,则检查缓冲区中剩余的空间是否足够容纳要写入的字节数,如果不够,则先将缓冲区中的数据刷新到磁盘中。然后,使用 System.arraycopy() 方法将要写入的数据拷贝到缓冲区中,并更新计数器 count。

最后,如果写入的字节数小于缓冲区长度且缓冲区中还有剩余空间,则直接将要写入的数据拷贝到缓冲区中,并更新计数器 count。

也就是说,只有当 buf 写满了,才会 flush,将数据刷到磁盘,默认一次刷 8192 个字节。

public BufferedOutputStream(OutputStream out) {
    this(out, 8192);
}

FileOutputStream 的 write 方法:

public void write(int b) throws IOException {
    write(b, append);
}

private native void write(int b, boolean append) throws IOException;

字符缓冲流


BufferedReader 类继承自 Reader 类,提供了一些便捷的方法,例如 readLine() 方法可以一次读取一行数据,而不是一个字符一个字符地读取。

BufferedWriter 类继承自 Writer 类,提供了一些便捷的方法,例如 newLine() 方法可以写入一个系统特定的行分隔符。

构造方法

  • BufferedReader(Reader in) :创建一个新的缓冲输入流,注意参数类型为Reader
  • BufferedWriter(Writer out): 创建一个新的缓冲输出流,注意参数类型为Writer
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));

字符缓冲流特有方法

  • BufferedReader:String readLine(): 读一行数据,读取到最后返回 null
  • BufferedWriter:newLine(): 换行,由系统定义换行符。
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
// 定义字符串,保存读取的一行文字
String line  = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine())!=null) {
    System.out.print(line);
    System.out.println("------");
}
// 释放资源
br.close();
// 创建流对象
BfferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
// 写出数据
bw.write("沉");
// 写出换行
bw.newLine();
bw.write("默");
bw.newLine();
bw.write("王");
bw.newLine();
bw.write("二");
bw.newLine();
// 释放资源
bw.close();

标签:字节,缓冲,写入,bw,缓冲区,new
From: https://www.cnblogs.com/sprinining/p/18336041

相关文章

  • .NET 高性能缓冲队列实现 BufferQueue
    目录前言适用场景功能说明使用示例BufferQueue内部设计概述Topic的隔离Partition的设计对并发的支持Partition的动态扩容Segment的回收机制Benchmark写入性能测试消费性能测试前言BufferQueue是一个用.NET编写的高性能的缓冲队列实现,支持多线程并发操作。项目是从moch......
  • 嵌入式学习第9天——C语言运算符,程序设计结构,输入输出缓冲机制
    2024.7.25第九天笔记关于++混合操作,不同计算结果推理第一种编译结果:inti=5;intsum=(++i)+(++i)=6+7=13第二种编译结果:inti=5;intsum=(++i)+(++i)=6+7=7+7前面的7是因为后面i的变化被影响后,重新赋值=14第一种编译结果:inti=5;in......
  • 如何在 2 个 GPU 之间发送缓冲区?
    我尝试将缓冲区A和缓冲区B分配给GPU0,然后将它们(缓冲区A和缓冲区B)分配给GPU1,并运行它们添加A+B的内核,并将其分配给缓冲区D(我之前在GPU中分配)1)我的问题是它在python中不起作用,在pycuda中不起作用,在cup中不起作用。我在PyCuda中尝试了这段代码,......
  • 使用 FFpyplayer 帧和 QPixmap 以及 MPEG-TS 格式的 UDP 流时出现追赶延时缓冲和滞后
    我正在尝试根据此帖子中找到的代码来构建我的用例。但是,我在使用pythonFFpyPlayer时遇到了麻烦;对于传统的ffplay,我没有这些问题。运行我的应用程序时,我注意到一种追赶延时缓冲效果,视频播放速度显着加快,然后恢复到正常速度。在某些视频中,我发......
  • golang 无缓冲区通道的 range 操作
     对一个无缓冲通道(chan)进行range操作意味着想要迭代并消费通道中的所有值。但是,由于无缓冲通道的特性,这种操作具有特定的行为和潜在的副作用,主要体现在以下几点: 阻塞行为:当你开始对无缓冲通道进行range操作时,每次循环迭代都会尝试从通道接收一个值。如果通......
  • 木舟0基础学习Java的第十八天(IO流,字节流,字符流,缓冲)
    IO流正常使用流程:1.抛异常 2.资源读写 3.关闭资源(从后往前关)字节流:(拷贝推荐使用)开发中一般不会抛出异常用try{}catch(){}也不推荐字节流读中文FileInputStream:读FileInputStreamfs=newFileInputStream("e:/b.txt");//11111111为-1的补......
  • C/C++ 避免缓冲区溢出的措施
    在C/C++中,缓冲区溢出是一种常见的安全问题,可以导致程序崩溃或安全漏洞。为了避免缓冲区溢出,可以采取以下防范措施:使用安全的函数:使用strncpy(), strncat(), snprintf()等函数代替strcpy(), strcat(), sprintf()等,这些函数允许你指定最大复制的字符数,从而避免溢出。......
  • tryhackme-Buffer Overflow Prep(缓冲区溢出准备)
    前景概述最开始接触二进制方式是因为参加比赛缺少一个pwn手,慢慢的学习在二进制方面懂了很多,学习了C和C++、基本的汇编语法、pwndbg、ollydbg等调试工具,以及在做pwn题目是相关的工具pwntools,学习了栈相关的基本知识,栈溢出相关的一些姿势,例如:ret2text、ret2plt、ret2shellcode、......
  • Qt开发: 推荐一个缓冲队列操作类的实现
    一.缓冲队列的背景    缓冲队列主要应用在生产者和消费者之间,保证数据的准确不丢失,提高效率。举个例子:如上图,假设点击按钮生成一个方块,方块生产出来需要耗时1s,生成完毕后显示在界面上;然后点击10下按钮,要生产10个按钮预计耗时10s。二.分析问题    点击按......
  • 缓冲器用在垃圾桶上怎么样?
    在我们的日常生活中,垃圾桶是不可或缺的一部分。然而,你是否曾想过,如果在垃圾桶上使用缓冲器,会带来怎样的变化呢? 首先,缓冲器能够极大地改善垃圾桶使用时的噪音问题。当我们用力合上垃圾桶盖时,常常会发出响亮的撞击声。这不仅会打破家居环境的宁静,在一些公共场合,如办公室、......