我想扩展以无缓冲方式将数据写入文件的现有代码。

该代码需要一个实现io.WriteCloser接口(interface)的编写器。因此,仅使用bufio.Writer包装现有文件是行不通的,因为它无法实现此接口(interface)。

如何制作bufio.Writer来实现并将必要的close调用传递给底层文件?

最佳答案

io.WriteCloser 是接口(interface):

type WriteCloser interface {
        Writer
        Closer
}

最终“规定”了这两种方法:
Write(p []byte) (n int, err error)

Close() error

bufio.Writer 已经具有Write()方法,因此要使其成为WriteCloser,只需一个Close()方法。

使用noop bufio.Writer方法扩展Close():
type MyWriteCloser struct {
    *bufio.Writer
}

func (mwc *MyWriteCloser) Close() error {
    // Noop
    return nil
}

类型*MyWriteCloser的值现在是WriteCloser。这是最简单的扩展。使用它:
bw := bufio.NewWriter(w)

mwc := &MyWriteCloser{bw}

尽管我们可以并且应该添加一个更有意义的Close()方法。由于bufio.Write会缓存写操作,因此在声明关闭之前,应先刷新其内部缓冲区:
func (mwc *MyWriteCloser) Close() error {
    return mwc.Flush()
}

还要注意,由于无法关闭bufio.Write(不提供Close()方法),因此不会关闭其基础io.Writer,这仅符合io.Closerio.WriteCloser接口(interface)。

如果您还想关闭基础文件,则还必须存储它,并且在调用bufio.Flush()(以确保所有内容都写完)之后,鉴于它没有返回任何错误,您可以继续关闭该文件。

它看起来像这样:
type MyWriteCloser struct {
    f *os.File
    *bufio.Writer
}

func (mwc *MyWriteCloser) Close() error {
    if err := mwc.Flush(); err != nil {
        return err
    }
    return mwc.f.Close()
}

使用它:
// Open a file:
f, err := os.Open("myfile.txt")
if err != nil {
    panic(err) // Handle error
}

mwc := &MyWriteCloser{f, bufio.NewWriter(f)}
defer mwc.Close()

// use mwc

10-06 13:16