diff --git a/vlib/os/file.v b/vlib/os/file.v index 1cd8388df8..ed3a08c94d 100644 --- a/vlib/os/file.v +++ b/vlib/os/file.v @@ -78,21 +78,42 @@ pub fn (mut f File) write_bytes_at(data voidptr, size, pos int) int { } // **************************** Read ops *************************** -// read_bytes reads an amount of bytes from the beginning of the file +// read_bytes reads bytes from the beginning of the file pub fn (f &File) read_bytes(size int) []byte { return f.read_bytes_at(size, 0) } -// read_bytes_at reads an amount of bytes at the given position in the file +// read_bytes_at reads bytes at the given position in the file pub fn (f &File) read_bytes_at(size, pos int) []byte { - // mut arr := [`0`].repeat(size) mut arr := []byte{len: size} - C.fseek(f.cfile, pos, C.SEEK_SET) - nreadbytes := C.fread(arr.data, 1, size, f.cfile) - C.fseek(f.cfile, 0, C.SEEK_SET) + nreadbytes := f.read_bytes_into(pos, arr) or { + // return err + return [] + } return arr[0..nreadbytes] } +// read_bytes_from fills `buf` with bytes at the given position in the file. +// `buf` must have length greater than zero. +// Returns number of bytes read or an error. +pub fn (f &File) read_bytes_into(pos int, mut buf []byte) ?int { + if buf.len == 0 { + panic(@FN + ': `buf.len` == 0') + } + // Note: fseek errors if pos == os.file_size, which we accept + C.fseek(f.cfile, pos, C.SEEK_SET) + // errno is only set if fread fails, so clear it first to tell + C.errno = 0 + nbytes := C.fread(buf.data, 1, buf.len, f.cfile) + if C.errno != 0 { + return error(posix_get_error_msg(C.errno)) + } + $if debug { + C.fseek(f.cfile, 0, C.SEEK_SET) + } + return nbytes +} + // **************************** Utility ops *********************** // write any unwritten data in stream's buffer pub fn (mut f File) flush() { diff --git a/vlib/os/os_test.v b/vlib/os/os_test.v index bfebb9c0ed..b84c924004 100644 --- a/vlib/os/os_test.v +++ b/vlib/os/os_test.v @@ -142,11 +142,19 @@ fn test_write_and_read_bytes() { // read_bytes_at with second parameter zeroed (size, 0). rbytes := file_read.read_bytes(5) - file_read.close() // eprintln('rbytes: $rbytes') // eprintln('payload: $payload') assert rbytes == payload + // check that trying to read data from EOF doesn't error and returns 0 + mut a := []byte{len: 5} + nread := file_read.read_bytes_into(5, a) or { + eprintln(err) + int(-1) + } + assert nread == 0 + + file_read.close() // We finally delete the test file. os.rm(file_name) }