【Golang】Go语言中缓冲bufio的原理解读与应用实战

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑

在这里插入图片描述

文章目录

  • Go语言中bufio
    • 一、bufio的基本概念和原理
    • 二、bufio的读操作
      • 1. 使用bufio.Reader读取文件内容
      • 2. 统计文件中字符、空格、数字和其他字符的数量
      • 3. 使用Scanner读取标准输入
    • 三、bufio的写操作
      • 1. 使用bufio.Writer写入文件内容
      • 2. 自定义io.Writer对象进行缓冲写
    • 四、bufio的缓冲区大小
      • 1. 默认缓冲区大小
      • 2. 自定义缓冲区大小

Go语言中bufio

bufio是Go语言标准库中的一个重要包,它提供了带缓冲的I/O操作,用于包装io.Reader或io.Writer对象,以减少I/O操作的次数,从而提高读写性能。本文将结合实际案例,详细讲解bufio在Go语言中的用法。
Go语言自带的IO操作包。bufio,使用这个包可以大幅提升文件的读写效率。
buf: 缓冲区.
io操作效率本身是还可以的,频繁访问本地磁盘文件(效率低)
所以说 bufio ,提供了一个缓冲区,读和写都先在缓冲区中,最后再一次性读取或者写入到文件里,降低访问本地磁盘的次数。
在这里插入图片描述

一、bufio的基本概念和原理

bufio的主要作用是减少I/O操作的次数,提供读写性能。其工作原理是通过在内存中维护一个缓冲区,先将数据读入缓冲区,再从缓冲区中读取数据,从而减少对底层I/O设备的访问次数。

bufio的主要对象是缓冲区,操作主要有两个:读和写。读操作时,如果缓冲区为空,则从文件读取数据填满缓冲区;如果缓冲区不为空,则从缓冲区读取数据。写操作时,如果缓冲区未满,则将数据写入缓冲区;如果缓冲区已满,则将缓冲区的数据写入文件,并继续写入剩余的数据。

二、bufio的读操作

bufio的读操作主要通过bufio.Reader对象实现,它提供了多种读取数据的方法,如Read、ReadLine、ReadString等。

1. 使用bufio.Reader读取文件内容

下面是一个使用bufio.Reader读取文件内容的示例:

package mainimport ("bufio""fmt""io""os"
)func main() {// 打开文件file, err := os.Open("example.txt")if err != nil {fmt.Println("read file err:", err)return}defer file.Close() // 使用defer关闭文件// 创建bufio.Reader对象。借助bufio来读取文件内容// func NewReader(rd io.Reader) *Readerreader := bufio.NewReader(file)// 循环读取文件内容for {// 通过Read方法Read()读取文件//buf := make([]byte, 1024)//n, err := bufioReader.Read(buf)//fmt.Println("读取到了多少个字节:", n)//读取到的内容//fmt.Println("读取到的内容:",string(buf[:n]))//通过ReadString方法读取文件// func (b *Reader) ReadString(delim byte) (string, error)//参数是以什么作为分隔符。读取得到的是字符串//注意,最后一行后面要是没有换行符,读取不到str, err := reader.ReadString('\n') // 读取字符串,以换行符为分隔符if err == io.EOF {                  // 判断文件是否结尾break} else if err != nil { // 判断错误,打印错误fmt.Printf("read file failed, err:%v", err)break}//循环中逐行打印出读取的内容fmt.Printf("read string SuccessFull: %s\n", str) // 打印读取的文件内容}
}

在这里插入图片描述

在这个示例中,我们首先使用os.Open函数打开文件,然后创建一个bufio.Reader对象,通过循环调用ReadString方法读取文件内容,每次读取一行。当遇到文件结尾时,ReadString方法会返回一个io.EOF错误,我们据此退出循环。

2. 统计文件中字符、空格、数字和其他字符的数量

下面是一个统计文件中字符、空格、数字和其他字符数量的示例:

package mainimport ("bufio""fmt""io""os"
)// CharCount 定义结构体
type CharCount struct {ChCount    intNumCount   intSpaceCount intOtherCount int
}func main() {// 打开文件file, err := os.Open("example.txt")if err != nil {fmt.Println("read file err:", err)return}defer file.Close() // 使用defer关闭文件// 创建bufio.Reader对象reader := bufio.NewReader(file)var count CharCount// 循环读取文件内容for {//str, err := reader.ReadString('\n') // 读取字符串,以换行符为分隔符str, _, err := reader.ReadLine() // 按行读取,最后一行没有换行符也能读到if err == io.EOF {               // 判断文件是否结尾break}if err != nil { // 判断错误,打印错误fmt.Printf("read file failed, err:%v", err)break}//runeArr := []rune(str) // 将字符串转为切片类型runeArr := str // 将字符串转为切片类型fmt.Println("得到的数据是", string(runeArr))for _, v := range runeArr { // 循环读取数组switch {case v >= 'a' && v <= 'z': // 判断是不是小写字母fallthroughcase v >= 'A' && v <= 'Z': // 判断是不是大写字母count.ChCount++case v == ' ' || v == '\t': // 判断是不是空格count.SpaceCount++case v >= '0' && v <= '9': // 判断是不是数字count.NumCount++default:count.OtherCount++}}}fmt.Printf("char count:%d\n", count.ChCount)fmt.Printf("num count:%d\n", count.NumCount)fmt.Printf("space count:%d\n", count.SpaceCount)fmt.Printf("other count:%d\n", count.OtherCount)
}

在这里插入图片描述

3. 使用Scanner读取标准输入

下面是一个使用bufio.Scanner读取标准输入的示例:

package mainimport ("bufio""fmt""os"
)func main() {// 读取键盘的输入// 键盘的输入,实际上是流 os.StdininputReader := bufio.NewReader(os.Stdin)// delim 到哪里结束读取 以换行符作为分隔符,之言不换行就可以一直读readString, _ := inputReader.ReadString('\n')fmt.Println("读取键盘输入的信息:", readString)
}

在这里插入图片描述

三、bufio的写操作

bufio的写操作主要通过bufio.Writer对象实现,它提供了多种写入数据的方法,如Write、WriteString、Flush等。

1. 使用bufio.Writer写入文件内容

下面是一个使用bufio.Writer写入文件内容的示例:

package mainimport ("bufio""fmt""os"
)func main() {// 打开文件句柄,以写的方式打开,如果文件不存在则创建file, err := os.OpenFile("F:\\goworks\\src\\jingtian\\yufa\\io操作\\bufio操作\\test_go_file.log",os.O_CREATE|os.O_WRONLY, 0644)if err != nil {fmt.Println("open file error:", err)return}defer file.Close() // 使用的defer语句关闭文件// 创建bufio.Writer对象fileWrite := bufio.NewWriter(file)inputStr := "Hello World ...\n"for i := 0; i < 10; i++ { // 循环写入数据fileWrite.WriteString(inputStr)}// 发现并没有写出到文件,是留在了缓冲区,所以我们需要调用 flush 刷新缓冲区// 必须手动刷新才能写入进文件fileWrite.Flush() // 刷新缓冲区,将数据写入文件
}

在这里插入图片描述

在这个示例中,我们首先使用os.OpenFile函数打开文件,然后创建一个bufio.Writer对象,通过循环调用WriteString方法写入文件内容。最后,我们调用Flush方法刷新缓冲区,将数据写入文件。

2. 自定义io.Writer对象进行缓冲写

下面是一个自定义io.Writer对象进行缓冲写的示例:

package mainimport ("bufio""fmt""io""strings"
)// 自定义一个io.Writer对象
type StringWriter struct{}func (s StringWriter) Write(p []byte) (n int, err error) {// 这里简单地将数据写入一个字符串变量(实际使用时,可以将其写入内存、文件等)fmt.Print(string(p))return len(p), nil
}func main() {// 创建一个StringWriter对象sw := StringWriter{}// 创建一个bufio.Writer对象,并传入StringWriter对象writer := bufio.NewWriterSize(sw, 10)// 写入数据writer.WriteString("Hello, ")writer.WriteString("world!\n")// 刷新缓冲区,将数据写入StringWriter对象writer.Flush()
}

在这个示例中,我们自定义了一个StringWriter对象,它实现了io.Writer接口的Write方法。然后,我们创建一个bufio.Writer对象,并传入StringWriter对象。接着,我们调用WriteString方法写入数据,并调用Flush方法刷新缓冲区,将数据写入StringWriter对象。

四、bufio的缓冲区大小

在bufio包中,Reader和Writer对象都有默认的缓冲区大小,但你也可以根据需要自定义缓冲区大小。

1. 默认缓冲区大小

对于bufio.Readerbufio.Writer,Go语言标准库为它们提供了默认的缓冲区大小。对于bufio.Reader,默认缓冲区大小通常是4096字节(4KB);对于bufio.Writer,默认缓冲区大小也是4096字节(但在某些实现中可能略有不同,具体取决于底层操作系统的I/O性能)。

2. 自定义缓冲区大小

如果你需要更大的缓冲区来提高性能,或者更小的缓冲区来减少内存使用,你可以使用bufio.NewReaderSizebufio.NewWriterSize函数来创建具有自定义缓冲区大小的Reader和Writer对象。

下面是一个自定义缓冲区大小的示例:

package mainimport ("bufio""fmt""os"
)func main() {// 打开文件file, err := os.OpenFile("F:\\goworks\\src\\jingtian\\yufa\\io操作\\bufio操作\\custom_buffer_file.log", os.O_CREATE|os.O_WRONLY, 0644)if err != nil {fmt.Println("open file error:", err)return}defer file.Close() // 使用defer语句关闭文件// 自定义缓冲区大小(例如:8KB)bufferSize := 8 * 1024// 创建具有自定义缓冲区大小的bufio.Writer对象fileWrite := bufio.NewWriterSize(file, bufferSize)inputStr := "This is a line with custom buffer size.\n"for i := 0; i < 10; i++ { // 循环写入数据_, err := fileWrite.WriteString(inputStr)if err != nil {fmt.Println("write file error:", err)return}}// 刷新缓冲区,将数据写入文件err = fileWrite.Flush()if err != nil {fmt.Println("flush buffer error:", err)return}fmt.Println("Data written to file successfully with custom buffer size.")
}

在这个示例中,我们创建了一个具有8KB缓冲区大小的bufio.Writer对象,并将其用于将数据写入文件。注意,在写入数据后,我们调用了Flush方法来确保缓冲区中的数据被写入文件。

对于bufio.Reader,你也可以使用类似的方法来创建具有自定义缓冲区大小的对象:

package mainimport ("bufio""fmt""os"
)func main() {// 打开文件file, err := os.Open("F:\\goworks\\src\\jingtian\\yufa\\io操作\\bufio操作\\custom_buffer_file.log")if err != nil {fmt.Println("read file error:", err)return}defer file.Close() // 使用defer语句关闭文件// 自定义缓冲区大小(例如:8KB)bufferSize := 8 * 1024// 创建具有自定义缓冲区大小的bufio.Reader对象fileRead := bufio.NewReaderSize(file, bufferSize)// 读取文件内容(这里只是简单地读取并打印每一行)for {line, err := fileRead.ReadString('\n')if err != nil {if err.Error() == "EOF" { // 判断是否到达文件末尾break}fmt.Println("read file error:", err)return}fmt.Print(line) // 打印读取到的行}fmt.Println("File read successfully with custom buffer size.")
}

在这个示例中,我们创建了一个具有8KB缓冲区大小的bufio.Reader对象,并将其用于读取文件内容。注意,在处理文件读取时,我们需要检查错误是否为EOF(文件末尾),以确定是否应该退出循环。

通过自定义缓冲区大小,你可以根据具体的应用场景和需求来优化bufio的性能和内存使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/443505.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Word中如何删除表格下一页的空白页

Reference&#xff1a; [1] Word空白页怎么都删除不掉&#xff1f;用这6个方法随便删&#xff01; - 知乎 (zhihu.com)

实现TCP Connect的断线重连机制:策略与实践

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 断线重连机制&#xff0c;它成为确保应用在网络不稳定情况下仍能持续提供服务的关键技术之一。本文旨在深入探讨TCP&#xff08;传输控制协…

使用Materialize制作unity的贴图,Materialize的简单教程,Materialize学习日志

Materialize 官网下载地址&#xff1a;http://boundingboxsoftware.com/materialize/ github源码地址&#xff1a;https://github.com/BoundingBoxSoftware/Materialize 下载地址&#xff1a;http://boundingboxsoftware.com/materialize/getkey.php 下载后解压运行exe即可 …

YoloV8改进策略:BackBone改进|CAFormer在YoloV8中的创新应用,显著提升目标检测性能

摘要 在目标检测领域,模型性能的提升一直是研究者和开发者们关注的重点。近期,我们尝试将CAFormer模块引入YoloV8模型中,以替换其原有的主干网络,这一创新性的改进带来了显著的性能提升。 CAFormer,作为MetaFormer框架下的一个变体,结合了深度可分离卷积和普通自注意力…

线性回归逻辑回归-笔记

一、线性回归&#xff08;Linear Regression&#xff09; 1. 定义 线性回归是一种用于回归问题的算法&#xff0c;旨在找到输入特征与输出值之间的线性关系。它试图通过拟合一条直线来最小化预测值与真实值之间的误差。 2. 模型表示 线性回归模型假设目标变量&#xff08;输…

深度学习基础—卷积神经网络示例

1.卷积神经网络的结构 在之前的博客《深度学习—简单的卷积神经网络》&#xff0c;仅由卷积层构成网络的全部&#xff0c;这还不是标准的网络结构&#xff0c;本文将继续介绍标准的卷积神经网络结构有哪些&#xff1f; 深度学习基础—简单的卷积神经网络https://blog.csdn.net…

[C++]使用纯opencv部署yolov11-seg实例分割onnx模型

【算法介绍】 在C中使用纯OpenCV部署YOLOv11-seg进行实例分割是一项具有挑战性的任务&#xff0c;因为YOLOv11通常是用PyTorch等深度学习框架实现的&#xff0c;而OpenCV本身并不直接支持加载和运行PyTorch模型。然而&#xff0c;可以通过一些间接的方法来实现这一目标&#x…

opencvjs 在前端的使用

一、opencv 官网 https://opencv.org/ 二、opencv是什么 三、opencvjs前端使用网站 https://docs.opencv.org/4.x/d0/d84/tutorial_js_usage.html https://docs.opencv.org/4.x/d5/d10/tutorial_js_root.html 四、opencvjs demo 举例 <!DOCTYPE html> <html>…

Ubuntu22.04之mpv播放器高频快捷键(二百七十)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

ML 系列:机器学习和深度学习的深层次总结( 15) — KNN — 第 1 部分

一、说明 K-最近邻 (KNN) 算法是一种流行的监督机器学习算法&#xff0c;用于分类和回归任务。它是非参数惰性学习算法的一个典型例子。KNN 被认为是一种惰性学习算法&#xff0c;因为它在训练阶段不对底层数据分布做出任何假设&#xff0c;也不从训练数据中学习特定模型。相反…

Golang | Leetcode Golang题解之第466题统计重复个数

题目&#xff1a; 题解&#xff1a; func getMaxRepetitions(s1 string, n1 int, s2 string, n2 int) int {n : len(s2)cnt : make([]int, n)for i : 0; i < n; i {// 如果重新给一个s1 并且s2是从第i位开始匹配 那么s2可以走多少位&#xff08;走完了就从头开始走p1, p2 :…

开发环境搭建之JAVA多个JDK版本安装

由于项目需要安装多个版本JDK、所以在此记录一下安装过程&#xff1a; 下载JDK1.8 11 17 等多个版本 简单粗暴一看就会、直接从官网下载exe安装包、然后配置环境变量即可 JDK1.8 JDK11 JDK17 安装完成之后如下图&#xff1a; 环境变量配置 右击“我的电脑”属性、找到…

Kron Reduction消去法如何操作,矩阵推导过程

三阶矩阵消去单节点 在电力系统中,母线上的电流注入始终为0,这样的节点可以通过一定的方法消除。以三节点为例,假设注入节点3的电流为0,则: [ I 1 I 2 I 3 ] = [ I 1 I 2 0 ] = [ Y 11 Y 12 Y 13 Y 21 Y 22 Y 23 Y 31 Y 32 Y 33 ] [ V 1 V 2 V 3 ] \left[\begin{array}{…

计算机网络:数据链路层 —— 数据链路层概述

文章目录 数据链路层主要功能 基本概念链路数据链路帧 数据链路层 在计算机网络中&#xff0c;链路层&#xff08;Data Link Layer&#xff09;是网络协议栈中的一层&#xff0c;负责管理和控制链路的建立、维护和释放&#xff0c;以及处理链路层的数据帧传输和错误控制等功能…

go发送邮件:在Go语言中实现发邮件的教程?

go发送邮件的教程指南&#xff1f;怎么使用Go语言发送电子邮件&#xff1f; Go语言&#xff0c;作为一种简洁、高效且并发性强的编程语言&#xff0c;自然也提供了丰富的库来支持邮件发送功能。AokSend将详细介绍如何在Go语言中实现发送邮件的功能&#xff0c;帮助你快速掌握这…

服务器数据恢复—硬盘坏扇区导致Linux系统服务器数据丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 一台linux操作系统网站服务器&#xff0c;该服务器上部署了几十个网站&#xff0c;使用一块SATA硬盘。 服务器故障&原因&#xff1a; 服务器在工作过程中突然宕机。管理员尝试重新启动服务器失败&#xff0c;于是将服务器上的硬盘拆下检测…

腾讯云SDK地址生成器

音视频终端 SDK&#xff08;腾讯云视立方&#xff09;将新版连麦管理方案的多个功能集成至 腾讯云视立方控制台 > 连麦管理&#xff0c;便于用户快捷使用&#xff0c;具体分为快速上手、连麦应用、用量统计和地址生成器四个功能页面。更多连麦功能说明&#xff0c;请参见 新…

查询v$asm_disk等待enq: DD - contention

1.两个节点查询v$asm_disk均卡住&#xff0c;等待enq: DD - contention&#xff0c;阻塞源头为rbal进程&#xff0c;rbal进程未发生阻塞&#xff0c;未在异常等待事件上。 2.阻塞源头RBAL&#xff0c;在CPU上运行。没有在做rebalance磁盘平衡。 3.diag诊断日志中&#xff0c;阻…

springboot 整合 rabbitMQ(2)

springboot 整合 rabbitMQ&#xff08;1&#xff09;-CSDN博客 上期说了rabbitMQ的基础用法&#xff08;普通队列模式&#xff09; 这期学习一下如何防止消息重复消费和进阶用法&#xff08;订阅者模式&#xff09; 目录 重复消费问题 导致 RabbitMQ 重复消费问题的原因&a…

《Windows PE》4.1.4 手工重构导入表

接下来我们做一个稍微复杂一些的实验&#xff0c;实验需要四个程序&#xff1a; HelloWorld.exe&#xff1a;弹出MessageBox窗口&#xff08;实验1已实现&#xff09;。 Regedit.exe&#xff1a;添加注册表启动项。 LockTray.exe&#xff1a;锁定任务栏窗口。 UnLockTray.exe&…