forked from TrueCloudLab/rclone
lib/readers: add GzipReader
This commit is contained in:
parent
4b981100db
commit
1f5e7ce598
2 changed files with 89 additions and 0 deletions
42
lib/readers/gzip.go
Normal file
42
lib/readers/gzip.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package readers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// gzipReader wraps a *gzip.Reader so it closes the underlying stream
|
||||||
|
// which the gzip library doesn't.
|
||||||
|
type gzipReader struct {
|
||||||
|
*gzip.Reader
|
||||||
|
in io.ReadCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGzipReader returns an io.ReadCloser which will read the stream
|
||||||
|
// and close it when Close is called.
|
||||||
|
//
|
||||||
|
// Unfortunately gz.Reader does not close the underlying stream so we
|
||||||
|
// can't use that directly.
|
||||||
|
func NewGzipReader(in io.ReadCloser) (io.ReadCloser, error) {
|
||||||
|
zr, err := gzip.NewReader(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gzipReader{
|
||||||
|
Reader: zr,
|
||||||
|
in: in,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the underlying stream and the gzip reader
|
||||||
|
func (gz *gzipReader) Close() error {
|
||||||
|
zrErr := gz.Reader.Close()
|
||||||
|
inErr := gz.in.Close()
|
||||||
|
if inErr != nil {
|
||||||
|
return inErr
|
||||||
|
}
|
||||||
|
if zrErr != nil {
|
||||||
|
return zrErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
47
lib/readers/gzip_test.go
Normal file
47
lib/readers/gzip_test.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package readers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rclone/rclone/lib/random"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type checkClose struct {
|
||||||
|
io.Reader
|
||||||
|
closed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cc *checkClose) Close() error {
|
||||||
|
cc.closed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGzipReader(t *testing.T) {
|
||||||
|
// Create some compressed data
|
||||||
|
data := random.String(1000)
|
||||||
|
var out bytes.Buffer
|
||||||
|
zw := gzip.NewWriter(&out)
|
||||||
|
_, err := io.Copy(zw, bytes.NewBufferString(data))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, zw.Close())
|
||||||
|
gzData := out.Bytes()
|
||||||
|
|
||||||
|
// Check we can decompress it
|
||||||
|
cc := &checkClose{Reader: bytes.NewBuffer(gzData)}
|
||||||
|
var decompressed bytes.Buffer
|
||||||
|
zr, err := NewGzipReader(cc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = io.Copy(&decompressed, zr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, data, string(decompressed.Bytes()))
|
||||||
|
|
||||||
|
// Check the underlying close gets called
|
||||||
|
assert.False(t, cc.closed)
|
||||||
|
require.NoError(t, zr.Close())
|
||||||
|
assert.True(t, cc.closed)
|
||||||
|
}
|
Loading…
Reference in a new issue