Last active
June 17, 2020 01:20
-
-
Save noncombatant/2b84000ce6bf0b7c8bfd906d7dc11a21 to your computer and use it in GitHub Desktop.
MaybeGzipReader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package maybegzip | |
import ( | |
"compress/gzip" | |
"io" | |
"os" | |
) | |
// Provides an io.Reader that might or might not refer to a gzipped file. If it | |
// is a gzipped file, reading from the io.Reader transparently decompresses the | |
// stream, and IsGzipped will be set to true. | |
// | |
// TODO: Consider supporting (transparently) all the compression formats that | |
// the Go standard library supports. The name would change to | |
// MaybeCompressedReader, IsGzipped would become an enum, et c. | |
type MaybeGzipReader struct { | |
// This Reader might refer to the original ReadSeeker passed to New (or the | |
// os.File created by Open), or it might refer to a gzip.Reader wrapping it. | |
// Check IsGzipped to find out. Either way, reading from it yields an | |
// uncompressed stream. | |
io.Reader | |
// Indicates whether or not Reader is a gzip.Reader. | |
IsGzipped bool | |
// If IsGzipped, this refers to the io.Closer that the gzip.Reader is | |
// wrapping. We use this to implement Close. | |
underlyingCloser io.Closer | |
} | |
func New(r io.ReadSeeker) (*MaybeGzipReader, error) { | |
gzr, e := gzip.NewReader(r) | |
if e != nil { | |
if e != gzip.ErrHeader && e != gzip.ErrChecksum { | |
return nil, e | |
} | |
_, e = r.Seek(0, io.SeekStart) | |
if e != nil { | |
return nil, e | |
} | |
// This type coercion (see also in Close) is nasty and may cause run-time | |
// panics. TODO: Find some clean way to fix that; create a ReadSeekCloser | |
// interface and make r be of that type? | |
return &MaybeGzipReader{Reader: r, IsGzipped: false, underlyingCloser: r.(io.Closer)}, nil | |
} | |
return &MaybeGzipReader{Reader: gzr, IsGzipped: true, underlyingCloser: r.(io.Closer)}, nil | |
} | |
func Open(pathname string) (*MaybeGzipReader, error) { | |
file, e := os.Open(pathname) | |
if e != nil { | |
return nil, e | |
} | |
return New(file) | |
} | |
func (r *MaybeGzipReader) Close() error { | |
e := r.Reader.(io.Closer).Close() | |
if e != nil { | |
return e | |
} | |
if r.IsGzipped { | |
e = r.underlyingCloser.Close() | |
if e != nil { | |
return e | |
} | |
} | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment