diff options
author | Russ Cox <rsc@golang.org> | 2009-08-27 18:36:45 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-08-27 18:36:45 -0700 |
commit | 221a44a481e44de4e7f8a8c872b11278f4f5db10 (patch) | |
tree | dc77ad283106ea5d91571e5af2999ddf844ac0e5 /src | |
parent | 3b32bf355aee497309c76f8a857b226aed14f75e (diff) | |
download | golang-221a44a481e44de4e7f8a8c872b11278f4f5db10.tar.gz |
os.File.ReadAt/WriteAt
R=r
DELTA=84 (81 added, 0 deleted, 3 changed)
OCL=34006
CL=34006
Diffstat (limited to 'src')
-rw-r--r-- | src/pkg/os/file.go | 47 | ||||
-rw-r--r-- | src/pkg/os/os_test.go | 40 |
2 files changed, 84 insertions, 3 deletions
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go index 958a8230c..c9c00788f 100644 --- a/src/pkg/os/file.go +++ b/src/pkg/os/file.go @@ -115,7 +115,7 @@ var EOF Error = eofError(0) // It returns the number of bytes read and an Error, if any. // EOF is signaled by a zero count with err set to EOF. // TODO(r): Add Pread, Pwrite (maybe ReadAt, WriteAt). -func (file *File) Read(b []byte) (ret int, err Error) { +func (file *File) Read(b []byte) (n int, err Error) { if file == nil { return 0, EINVAL } @@ -132,10 +132,31 @@ func (file *File) Read(b []byte) (ret int, err Error) { return n, err } +// ReadAt reads len(b) bytes from the File starting at byte offset off. +// It returns the number of bytes read and the Error, if any. +// EOF is signaled by a zero count with err set to EOF. +// ReadAt always returns a non-nil Error when n != len(b). +func (file *File) ReadAt(b []byte, off int64) (n int, err Error) { + if file == nil { + return 0, EINVAL; + } + for len(b) > 0 { + m, e := syscall.Pread(file.fd, b, off); + n += m; + if e != 0 { + err = &PathError{"read", file.name, Errno(e)}; + break; + } + b = b[m:len(b)]; + off += int64(m); + } + return; +} + // Write writes len(b) bytes to the File. // It returns the number of bytes written and an Error, if any. -// If the byte count differs from len(b), it usually implies an error occurred. -func (file *File) Write(b []byte) (ret int, err Error) { +// Write returns a non-nil Error when n != len(b). +func (file *File) Write(b []byte) (n int, err Error) { if file == nil { return 0, EINVAL } @@ -157,6 +178,26 @@ func (file *File) Write(b []byte) (ret int, err Error) { return n, err } +// WriteAt writes len(b) bytes to the File starting at byte offset off. +// It returns the number of bytes written and an Error, if any. +// WriteAt returns a non-nil Error when n != len(b). +func (file *File) WriteAt(b []byte, off int64) (n int, err Error) { + if file == nil { + return 0, EINVAL; + } + for len(b) > 0 { + m, e := syscall.Pwrite(file.fd, b, off); + n += m; + if e != 0 { + err = &PathError{"write", file.name, Errno(e)}; + break; + } + b = b[m:len(b)]; + off += int64(m); + } + return; +} + // Seek sets the offset for the next Read or Write on file to offset, interpreted // according to whence: 0 means relative to the origin of the file, 1 means // relative to the current offset, and 2 means relative to the end. diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go index 84c4d15a0..9f7df2ac5 100644 --- a/src/pkg/os/os_test.go +++ b/src/pkg/os/os_test.go @@ -628,3 +628,43 @@ func TestHostname(t *testing.T) { t.Errorf("Hostname() = %q, want %q", hostname, want); } } + +func TestReadAt(t *testing.T) { + f, err := Open("_obj/readtest", O_CREAT|O_RDWR|O_TRUNC, 0666); + if err != nil { + t.Fatalf("open _obj/readtest: %s", err); + } + const data = "hello, world\n"; + io.WriteString(f, data); + + b := make([]byte, 5); + n, err := f.ReadAt(b, 7); + if err != nil || n != len(b) { + t.Fatalf("ReadAt 7: %d, %r", n, err); + } + if string(b) != "world" { + t.Fatalf("ReadAt 7: have %q want %q", string(b), "world"); + } +} + +func TestWriteAt(t *testing.T) { + f, err := Open("_obj/writetest", O_CREAT|O_RDWR|O_TRUNC, 0666); + if err != nil { + t.Fatalf("open _obj/writetest: %s", err); + } + const data = "hello, world\n"; + io.WriteString(f, data); + + n, err := f.WriteAt(strings.Bytes("WORLD"), 7); + if err != nil || n != 5 { + t.Fatalf("WriteAt 7: %d, %v", n, err); + } + + b, err := io.ReadFile("_obj/writetest"); + if err != nil { + t.Fatalf("ReadFile _obj/writetest: %v", err); + } + if string(b) != "hello, WORLD\n" { + t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n"); + } +} |