首页 > 解决方案 > 如何有效地对文件进行多次写入

问题描述

我需要在 Go 中将多行写入文件。这些行将由另一种方法生成。因此,要写入文件,我想写入文件的次数与行数一样多。但是写入文件是一项昂贵的操作。我正在考虑一种非常乐观的写入文件的方式。我可以在这里使用什么数据结构?

标签: godata-structures

解决方案


要分摊操作系统文件读取和写入的成本,请使用 Go 标准库bufio包。


这里有一个 Go 基准来说明这一点:bufio速度要快得多。

$ go test bufio_test.go -bench=.
goos: linux
goarch: amd64
BenchmarkBufioWrite-4    50     20887474 ns/op    6774811 B/op    147938 allocs/op
BenchmarkOSWrite-4        3    387543398 ns/op    6022413 B/op    104415 allocs/op
$

bufio_test.go

package main

import (
    "bufio"
    "io/ioutil"
    "os"
    "strings"
    "testing"
)

func BenchmarkBufioWrite(b *testing.B) {
    b.ReportAllocs()
    b.ResetTimer()
    for N := 0; N < b.N; N++ {
        out, err := ioutil.TempFile(``, `StackOverflow`)
        if err != nil {
            b.Fatal(err)
        }
        outName := out.Name()
        w := bufio.NewWriter(out)
        for _, line := range benchLines {
            _, err := w.Write([]byte(line))
            if err != nil {
                b.Fatal(err)
            }
        }
        err = w.Flush()
        if err != nil {
            b.Fatal(err)
        }
        err = out.Close()
        if err != nil {
            b.Fatal(err)
        }
        os.Remove(outName)
    }
}

func BenchmarkOSWrite(b *testing.B) {
    b.ReportAllocs()
    b.ResetTimer()
    for N := 0; N < b.N; N++ {
        out, err := ioutil.TempFile(``, `StackOverflow`)
        if err != nil {
            b.Fatal(err)
        }
        outName := out.Name()
        w := out
        for _, line := range benchLines {
            _, err := w.Write([]byte(line))
            if err != nil {
                b.Fatal(err)
            }
        }
        err = out.Close()
        if err != nil {
            b.Fatal(err)
        }
        os.Remove(outName)
    }
}

var benchLines = func() []string {
    // The Complete Works of William Shakespeare by William Shakespeare
    // http://www.gutenberg.org/files/100/100-0.txt
    data, err := ioutil.ReadFile(`/home/peter/shakespeare.100-0.txt`)
    if err != nil {
        panic(err)
    }
    return strings.Split(string(data), "\n")
}()

推荐阅读