I've got some code which should read gzipp'ed and non-gzipp'ed files. For that I have an open method which wraps the reader in a zip reader if the filename ends with gz.
My assumptions are that A) calls to os.File.Read() are *not* buffered so I want to wrap them in a bufio.Reader() and B) that I must call Close().
I'm trying to do something like this:
func open(filename string) (io.ReadCloser, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
var r io.ReadCloser
r = bufio.NewReader(f) // does not compile
if path.Ext(filename) != "gz" {
return r, nil
}
return gzip.NewReader(r)
}
But
a) r = bufio.NewReader(f) does not work since it doesn't implement io.ReadCloser
b) Do I still need to close the file after I've wrapped it in a bufio.Reader?
Right now I have an open function which creates a struct which implements ReadCloser so that I can always call Close() (Note that this doesn't solve the "close the buffered file" problem):
type CfpFile struct {
Filename string
R io.Reader
RC io.ReadCloser
}
func (f *CfpFile) Read(p []byte) (n int, err error) {
if f.RC != nil {
return f.RC.Read(p)
}
return f.R.Read(p)
}
func (f *CfpFile) Close() error {
if f.RC != nil {
return f.RC.Close()
}
return nil
}
func openCfpFile(filename string) (*CfpFile, error) {
const bufSize = 4 * 1 << 20
f, err := os.Open(filename)
if err != nil {
log.Printf("Error opening %s", filename)
return nil, err
}
if path.Ext(filename) != "gz" {
return &CfpFile{Filename: filename, R: bufio.NewReaderSize(f, bufSize)}, nil
}
rc, err := gzip.NewReader(bufio.NewReaderSize(f, bufSize))
if err != nil {
log.Print("gzip.NewReader: ", err)
return nil, err
}
return &CfpFile{Filename: filename, RC: rc}, nil
}
Is this the right approach?
Frank