GO 利用bufio包(流式操作) - 并发写文件/读文件示例

简介: GO 利用bufio包(流式操作) - 并发写文件/读文件示例

 并发写文件:

注意点:

    • runtime.GOMAXPROCS(runtime.NumCPU()) 限制并发写操作的协程数:

    协程数不宜过多,避免协程间的频繁切换影响性能(根据cpu核数而定)

    • WriteString()操作要加锁,否则最终写入数据有问题(乱码等...)
    • 最后记得Flush()一下:

    bufio 通过 flush 操作将缓冲写入真实的文件的,所以一定要在关闭文件之前先flush,否则会造成数据丢失的情况

    packagemainimport (
    "bufio""fmt""os""runtime""runtime/debug""sync")
    // bufio库的流式处理  如果文件较小,使用ioutil也不失为一种方法funcWriteDataToTxt() {
    txtFile, err :=os.OpenFile("55555.txt", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0777) // O_TRUNC 清空重写iferr!=nil {
    fmt.Println("WriteDataToTxt os.OpenFile() err:", err)
    return    }
    defertxtFile.Close()
    // txtFile.WriteString() // os操作文件-效率低bufWriter :=bufio.NewWriter(txtFile)
    varwgsync.WaitGrouplimitChan :=make(chanstruct{}, runtime.GOMAXPROCS(runtime.NumCPU())) // 最大并发协程数varmutexsync.Mutexfori :=0; i<10000; i++ { // 写1w行测试limitChan<-struct{}{}
    wg.Add(1)
    gofunc(jint) {
    deferfunc() {
    ife :=recover(); e!=nil {
    fmt.Printf("WriteDataToTxt panic: %v,stack: %s\n", e, debug.Stack())
    // return                }
    wg.Done()
    <-limitChan            }()
    // 模拟业务逻辑:先整合所有数据,然后再统一写WriteString()strId :=fmt.Sprintf("%v", j)
    strName :=fmt.Sprintf(" user_%v", j)
    strScore :=fmt.Sprintf(" %d", j*10)
    mutex.Lock() // 要加锁/解锁,否则 bufWriter.WriteString 写入数据有问题_, err :=bufWriter.WriteString(strId+strName+strScore+"\n")
    iferr!=nil {
    fmt.Printf("WriteDataToTxt WriteString err: %v\n", err)
    return            }
    mutex.Unlock()
    // bufWriter.Flush() // 刷入磁盘(错误示例:WriteDataToTxt err: short write,short write;因为循环太快,有时写入的数据量太小了)        }(i)
        }
    wg.Wait()
    bufWriter.Flush() // 刷入磁盘(正确示例,bufio 通过 flush 操作将缓冲写入真实的文件的,所以一定要在关闭文件之前先flush,否则会造成数据丢失的情况)}

    image.gif

    报错:

    image.gif编辑

    读文件:

    注意点:

      • 读取文件中一行内容时,ReadSliceReadLine性能优于ReadBytesReadString,但由于ReadLine对换行的处理更加全面(兼容\n\r\n换行),因此,实际开发过程中,建议使用ReadLine函数。
      • 关于os.File、bufio、ioutil 写文件的性能比较,参考:
        https://segmentfault.com/a/1190000023691973
      packagemainimport (
      "bufio""fmt""io""os")
      // 读文件funcReadDataFromTxt() {
      txtFile, err :=os.OpenFile("55555.txt", os.O_RDONLY, 0777) // O_TRUNC 清空重写iferr!=nil {
      fmt.Println("WriteDataToTxt os.OpenFile() err:", err)
      return    }
      defertxtFile.Close()
      bufReader :=bufio.NewReader(txtFile)
      for {
      data, _, err :=bufReader.ReadLine() // 读一行日志iferr==io.EOF {                   // 如果列表读完了,退出fmt.Println("数据读完了~")
      break        }
      fmt.Println("data: ", string(data))
          }
      return}

      image.gif


      相关文章
      Go语言包的组织与导入 -《Go语言实战指南》
      本章详细介绍了Go语言中的包(Package)概念及其使用方法。包是实现代码模块化、复用性和可维护性的核心单位,内容涵盖包的基本定义、命名规则、组织结构以及导入方式。通过示例说明了如何创建和调用包,并深入讲解了`go.mod`文件对包路径的管理。此外,还提供了多种导入技巧,如别名导入、匿名导入等,帮助开发者优化代码结构与可读性。最后以表格形式总结了关键点,便于快速回顾和应用。
      126 61
      Go入门实战:并发模式的使用
      本文详细探讨了Go语言的并发模式,包括Goroutine、Channel、Mutex和WaitGroup等核心概念。通过具体代码实例与详细解释,介绍了这些模式的原理及应用。同时分析了未来发展趋势与挑战,如更高效的并发控制、更好的并发安全及性能优化。Go语言凭借其优秀的并发性能,在现代编程中备受青睐。
      107 33
      Go语言包与模块(module)的基本使用-《Go语言实战指南》
      本章深入讲解Go语言中的包(Package)和模块(Module)概念。包是代码组织的最小单位,每个`.go`文件属于一个包,通过`import`实现复用;主程序包需命名为`main`。模块是Go 1.11引入的依赖管理机制,支持自动版本管理和私有/远程仓库,无需依赖GOPATH。通过实际示例,如自定义包`mathutil`和第三方模块`gin`的引入,展示其使用方法。常用命令包括`go mod init`、`go mod tidy`等,帮助开发者高效管理项目依赖。最后总结,包负责功能划分,模块实现现代化依赖管理,提升团队协作效率。
      102 15
      用 Go 实现一个轻量级并发任务调度器(支持限速)
      本文介绍了如何用 Go 实现一个轻量级的并发任务调度器,解决日常开发中批量任务处理的需求。调度器支持最大并发数控制、速率限制、失败重试及结果收集等功能。通过示例代码展示了其使用方法,并分析了核心组件设计,包括任务(Task)和调度器(Scheduler)。该工具适用于网络爬虫、批量请求等场景。文章最后总结了 Go 并发模型的优势,并提出了扩展功能的方向,如失败回调、超时控制等,欢迎读者交流改进。
      118 25
      Go 语言中的 Sync.Map 详解:并发安全的 Map 实现
      `sync.Map` 是 Go 语言中用于并发安全操作的 Map 实现,适用于读多写少的场景。它通过两个底层 Map(`read` 和 `dirty`)实现读写分离,提供高效的读性能。主要方法包括 `Store`、`Load`、`Delete` 等。在大量写入时性能可能下降,需谨慎选择使用场景。
      Go语言中的包(package)是如何组织的?
      在Go语言中,包是代码组织和管理的基本单元,用于集合相关函数、类型和变量,便于复用和维护。包通过目录结构、文件命名、初始化函数(`init`)及导出规则来管理命名空间和依赖关系。合理的包组织能提高代码的可读性、可维护性和可复用性,减少耦合度。例如,`stringutils`包提供字符串处理函数,主程序导入使用这些函数,使代码结构清晰易懂。
      267 11
      怎么禁用 vscode 中点击 go 包名时自动打开浏览器跳转到 pkg.go.dev
      本文介绍了如何在 VSCode 中禁用点击 Go 包名时自动打开浏览器跳转到 pkg.go.dev 的功能。通过将 gopls 的 `ui.navigation.importShortcut` 设置为 &quot;Definition&quot;,可以实现仅跳转到定义处而不打开链接。具体操作步骤包括:打开设置、搜索 gopls、编辑 settings.json 文件并保存更改,最后重启 VSCode 使设置生效。
      223 8
      怎么禁用 vscode 中点击 go 包名时自动打开浏览器跳转到 pkg.go.dev
      |
      8月前
      |
      go语言使用strings包
      go语言使用strings包
      155 3
      Go 语言基础:包、函数、语句和注释解析
      一个 Go 文件包含以下几个部分: 包声明 导入包 函数 语句和表达式 看下面的代码,更好地理解它:
      98 0
      go 包变量函数
      go 包变量函数
      55 0
      AI助理

      你好,我是AI助理

      可以解答问题、推荐解决方案等

      登录插画

      登录以查看您的控制台资源

      管理云资源
      状态一览
      快捷访问