getFileSize and setFileSize procedures for File and AsyncFile

Platform independent procedure to set a file length. Useful when
replacing file content.
This commit is contained in:
Emery Hemingway
2017-04-04 20:26:59 -05:00
parent 4ba6f9808e
commit bc5c2d8414
4 changed files with 34 additions and 5 deletions

View File

@@ -70,14 +70,16 @@ else:
result = O_RDWR
result = result or O_NONBLOCK
proc getFileSize(f: AsyncFile): int64 =
proc getFileSize*(f: AsyncFile): int64 =
## Retrieves the specified file's size.
when defined(windows) or defined(nimdoc):
var high: DWord
let low = getFileSize(f.fd.Handle, addr high)
if low == INVALID_FILE_SIZE:
raiseOSError(osLastError())
return (high shl 32) or low
result = (high shl 32) or low
else:
result = lseek(f.fd.cint, 0, SEEK_END)
proc openAsync*(filename: string, mode = fmRead): AsyncFile =
## Opens a file specified by the path in ``filename`` using
@@ -466,6 +468,22 @@ proc write*(f: AsyncFile, data: string): Future[void] =
addWrite(f.fd, cb)
return retFuture
proc setFileSize*(f: AsyncFile, length: int64) =
## Set a file length.
when defined(windows) or defined(nimdoc):
var
high = (length shr 32).Dword
let
low = (length and 0xffffffff).Dword
status = setFilePointer(f.fd.Handle, low, addr high, 0)
lastErr = osLastError()
if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or
(setEndOfFile(f.fd.Handle) == 0):
raiseOSError(osLastError())
else:
if ftruncate(f.fd.cint, length) == -1:
raiseOSError(osLastError())
proc close*(f: AsyncFile) =
## Closes the file specified.
unregister(f.fd)
@@ -498,4 +516,4 @@ proc readToStream*(f: AsyncFile, fs: FutureStream[string]) {.async.} =
break
await fs.write(data)
fs.complete()
fs.complete()

View File

@@ -2895,6 +2895,9 @@ when not defined(JS): #and not defined(nimscript):
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
## retrieves the file size (in bytes) of `f`.
proc setFileSize*(f: File, size: int64) {.tags: [ReadIOEffect], benign.}
## changes the size of file `f` (in bytes).
proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns

View File

@@ -52,6 +52,8 @@ proc c_ferror(f: File): cint {.
importc: "ferror", header: "<stdio.h>", tags: [].}
proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {.
importc: "setvbuf", header: "<stdio.h>", tags: [].}
proc c_ftruncate(f: FileHandle, len: clong): cint {.
importc: "ftruncate", header: "<unistd.h>".}
proc raiseEIO(msg: string) {.noinline, noreturn.} =
sysFatal(IOError, msg)
@@ -373,6 +375,11 @@ proc getFileSize(f: File): int64 =
result = getFilePos(f)
setFilePos(f, oldPos)
proc setFileSize(f: File, size: int64) =
## Set a file length.
if c_ftruncate(getFileHandle f, size.clong) == -1:
raiseEIO("cannot truncate file")
proc readFile(filename: string): TaintedString =
var f: File
if open(f, filename):

View File

@@ -11,9 +11,10 @@ proc main() {.async.} =
# Simple write/read test.
block:
var file = openAsync(fn, fmReadWrite)
await file.write("test")
await file.write("testing")
file.setFilePos(0)
await file.write("foo")
file.setFileSize(4)
file.setFilePos(0)
let data = await file.readAll()
doAssert data == "foot"
@@ -24,7 +25,7 @@ proc main() {.async.} =
var file = openAsync(fn, fmAppend)
await file.write("\ntest2")
let errorTest = file.readAll()
echo await errorTest
yield errorTest
doAssert errorTest.failed
file.close()
file = openAsync(fn, fmRead)