summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-08-27 18:36:45 -0700
committerRuss Cox <rsc@golang.org>2009-08-27 18:36:45 -0700
commit221a44a481e44de4e7f8a8c872b11278f4f5db10 (patch)
treedc77ad283106ea5d91571e5af2999ddf844ac0e5 /src
parent3b32bf355aee497309c76f8a857b226aed14f75e (diff)
downloadgolang-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.go47
-rw-r--r--src/pkg/os/os_test.go40
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");
+ }
+}