I want the func OpenFile() to read gzip files and bzip2 files. I will add other types later.
func OpenFile(name string) io.Reader{
file, err := os.Open(name)
if err != nil {
log.Fatal(err)
}
if(strings.Contains(name, ".gz")){
gzip, gerr := gzip.NewReader(file)
if gerr != nil {
log.Fatal(gerr)
}
return gzip
}else if(strings.Contains(name, ".bz2")){
bzip2 := bzip2.NewReader(file)
return bzip2
}else{
return file
}
}
I call the OpenFile() in another function A:
in := OpenFile(p)
for _, d := range fdb.Detect(in) {
set[d] = true
counter++
}
...
My issue is that if I use "defer file.Close()" in OpenFile(), the file would be closed too early so I can't get any input value. How can I close the file in A?
Notice that the gzip.NewReader(file) and the bzip2.NewReader(file) return different interfaces.
gzip: func NewReader(r io.Reader) (*Reader, error) // Reader has a func Close()
bzip2: func NewReader(r io.Reader) io.Reader // io.Reader doesn't have a func Close()
This is the reason that I can't return NewReader(file) in the first place.
Thank you!
As others have mentioned, you should return an io.ReadCloser
from your function. Since the return value of bzip2.NewReader()
does not satisfy io.ReadCloser
, you'll need to create your own type.
type myFileType struct {
io.Reader
io.Closer
}
func OpenFile(name string) io.ReadCloser {
file, err := os.Open(name)
if err != nil {
log.Fatal(err)
}
if strings.Contains(name, ".gz") {
gzip, gerr := gzip.NewReader(file)
if gerr != nil {
log.Fatal(gerr)
}
return gzip
} else if strings.Contains(name, ".bz2") {
bzip2 := bzip2.NewReader(file)
return myFileType{bzip2, file}
} else {
return file
}
}