diff --git a/pkging/file.go b/pkging/file.go index c7d12a1..d02acff 100644 --- a/pkging/file.go +++ b/pkging/file.go @@ -26,6 +26,13 @@ type File interface { // Read reads up to len(b) bytes from the File. It returns the number of bytes read and any error encountered. At end of file, Read returns 0, io.EOF. Read(p []byte) (int, error) + // ReadAt implements the ReadAt interface for File + // (reads len(b) bytes from the File starting at byte offset off. + // It returns the number of bytes read and the error, if any. + // ReadAt always returns a non-nil error when n < len(b). + // At end of file, that error is io.EOF) + ReadAt(p []byte, offset int64) (int, error) + // Readdir reads the contents of the directory associated with file and returns a slice of up to n FileInfo values, as would be returned by Lstat, in directory order. Subsequent calls on the same file will yield further FileInfos. // // If n > 0, Readdir returns at most n FileInfo structures. In this case, if Readdir returns an empty slice, it will return a non-nil error explaining why. At the end of a directory, the error is io.EOF. diff --git a/pkging/mem/file.go b/pkging/mem/file.go index 2d4d244..846128d 100644 --- a/pkging/mem/file.go +++ b/pkging/mem/file.go @@ -81,6 +81,21 @@ func (f *File) Read(p []byte) (int, error) { return 0, fmt.Errorf("unable to read %s", f.Name()) } +// ReadAt implements the ReadAt interface for File +// (reads len(b) bytes from the File starting at byte offset off. +// It returns the number of bytes read and the error, if any. +// ReadAt always returns a non-nil error when n < len(b). +// At end of file, that error is io.EOF) +func (f *File) ReadAt(p []byte, offset int64) (int, error) { + if len(f.data) == 0 || offset >= int64(len(f.data)) { + return 0, io.EOF + } + + f.reader = bytes.NewReader(f.data[offset:]) + + return f.reader.Read(p) +} + // Write writes len(b) bytes to the File. It returns the number of bytes written and an error, if any. Write returns a non-nil error when n != len(b). func (f *File) Write(b []byte) (int, error) { if f.writer == nil { diff --git a/pkging/mem/file_test.go b/pkging/mem/file_test.go index 5ebb32b..83cdde6 100644 --- a/pkging/mem/file_test.go +++ b/pkging/mem/file_test.go @@ -60,3 +60,29 @@ func Test_File_Seek(t *testing.T) { r.NotEqual(data, b) r.Equal([]byte("the arm"), b) } + +func TestFileReadAt(t *testing.T) { + r := require.New(t) + + info, err := here.Current() + r.NoError(err) + + pkg, err := New(info) + r.NoError(err) + + f, err := pkg.Create(":/tolstoy") + r.NoError(err) + + data := []byte("pierre always loved natasha") + f.Write(data) + r.NoError(f.Close()) + + f, err = pkg.Open(":/tolstoy") + r.NoError(err) + + b := make([]byte, len(data)) + read, err := f.ReadAt(b, 7) + r.NoError(err) + r.Equal("always loved natasha", string(b[:read])) + r.Equal(read, len(data[7:])) +}