Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a bufio.Writer that implements io.WriteCloser

Tags:

io

go

I want to extend existing code that writes data to a file in an unbuffered way.

The code expects a writer that implements the io.WriteCloser interface. Therefore just wrapping the existing file with a bufio.Writer does not work, as it does not implement this interface.

How can I make a bufio.Writer to implement and pass the necessary close call to the underlaying file?

like image 376
Robert Avatar asked Mar 30 '17 10:03

Robert


1 Answers

io.WriteCloser is the interface:

type WriteCloser interface {
        Writer
        Closer
}

Which ultimately "prescribes" these 2 methods:

Write(p []byte) (n int, err error)

Close() error

bufio.Writer already has a Write() method, so to make it a WriteCloser, only a Close() method is needed.

Extending bufio.Writer with a noop Close() method:

type MyWriteCloser struct {
    *bufio.Writer
}

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

A value of type *MyWriteCloser is now a WriteCloser. This is the easiest extension. Using it:

bw := bufio.NewWriter(w)

mwc := &MyWriteCloser{bw}

Although we can –and we should– add a more meaningful Close() method. As bufio.Write does buffered writes, we should flush its internal buffer before we declare it closed:

func (mwc *MyWriteCloser) Close() error {
    return mwc.Flush()
}

Also note that since bufio.Write cannot be closed (does not provide a Close() method), this will not close its underlying io.Writer, this is just to conform to the io.Closer and io.WriteCloser interfaces.

If you also want to close the underlying file, you also have to store it, and after calling bufio.Flush() (to make sure everything is written out), given it's not returning any errors, you may proceed to also close the file.

This is how it could look like:

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()
}

Using it:

// 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
like image 188
icza Avatar answered Oct 20 '22 03:10

icza