1
mirror of https://github.com/rclone/rclone synced 2024-12-23 14:23:44 +01:00

lib/readers: add GzipReader

This commit is contained in:
Nick Craig-Wood 2022-07-29 16:39:02 +01:00
parent 4b981100db
commit 1f5e7ce598
2 changed files with 89 additions and 0 deletions

42
lib/readers/gzip.go Normal file
View 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
View 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)
}