Module similar to std/memfiles but better layered & no exceptions interface which can help w/fancy file making needs or safety inside || blocks. Also adds noShrink safety, has non-system.open-colliding type constructor, uses .len (not .size) for more Nim-wide consistency & supports WO memory, and has FileInfo in the object (for various inspections).
Types
MFile = object fd*: cint ## open file|-1; open_osfhandle(fh,) on Win; FileHandle=cint fi*: FileInfo ## File metadata at time of open when defined(windows): fh*: cint ## Underlying OS File Handle; fdclose(fd) auto-closes this mh*: Handle ## M)ap H)andle *CAUTION*: Windows specific public field prot*: cint ## Map Protection flags*: cint ## Map Flags (-1 => not open) mslc*: MSlice ## (mem, len) of file
- Like MemFile but safe in an MT-environment
Procs
proc mopen(fd, fh: cint; fi: FileInfo; prot = PROT_READ; flags = MAP_SHARED; a = 0.Off; b = Off(-1); allowRemap = false; noShrink = false; err = stderr): MFile {....raises: [], tags: [WriteIOEffect], forbids: [].}
- mmap(2) wrapper to simplify life. Byte range [a,b) of the file pointed to by 'fd' translates to [result.mem ..< .len).
proc mopen(fh: cint; prot = PROT_READ; flags = MAP_SHARED; a = 0; b = Off(-1); allowRemap = false; noShrink = false; err = stderr): MFile {. ...raises: [], tags: [WriteIOEffect], forbids: [].}
- Init map for already open fh. See mopen(cint, Stat) for details.
proc mopen(path: string; prot = PROT_READ; flags = MAP_SHARED; a = 0; b = -1; allowRemap = false; noShrink = false; perMask = 0o000000000666; err = stderr): MFile {....raises: [], tags: [WriteIOEffect], forbids: [].}
- Init map for path. See mopen(cint,Stat) for mapping details. This proc also creates a file, if necessary, with permission perMask.
proc nSplit(n: int; path: string; sep = '\n'; prot = PROT_READ; flags = MAP_SHARED): tuple[mf: MFile, parts: seq[MSlice]] {. ...raises: [], tags: [WriteIOEffect], forbids: [].}
- Split seekable file @path into n roughly equal sep-delimited parts with any separator char included in slices. Caller should close result.mf (which is nil on failure) when desired. result.len can be < n for small file sizes (in number of seps). For IO efficiency, subdivision is done by bytes as a guess. So, this is fast, but accuracy is limited by statistical regularity.
Iterators
iterator lines(mf: MFile; buf: var string; sep = '\n'; eat = '\r'): string {. ...raises: [], tags: [], forbids: [].}
-
Copy each line in mf to passed buf, like system.lines(File). sep, eat, and delimiting logic is as for mslice.mSlices, but Nim strings are returned. Default parameters parse lines ending in either Unix(\n) or Windows(\r\n) style on on a line-by-line basis (not every line needs the same ending). sep='\\r', eat='\\0' parses archaic MacOS9 files.
var buffer: string = "" for line in lines(mopen("foo"), buffer): echo line
iterator mSlices(mf: MFile; sep = '\n'; eat = '\r'): MSlice {....raises: [], tags: [], forbids: [].}
iterator mSlices(path: string; sep = '\n'; eat = '\r'; keep = false; err = stderr; mf: var MFile = doNotUse): MSlice {....raises: [], tags: [WriteIOEffect], forbids: [].}
- A convenient input iterator that mopen()s path or if that fails falls back to ordinary file IO but constructs MSlice from lines. true keep means MFile or strings backing MSlice's are kept alive for life of program unless you also pass mf which returns the MFile to close when unneeded.
iterator rows(f: File; s: Sep; n = 0): seq[string] {....raises: [IOError], tags: [ReadIOEffect], forbids: [].}
- Exactly like rows(File, Sep) but yields new Nim seqs.
iterator rows(f: File; s: Sep; row: var seq[string]; n = 0): seq[string] {. ...raises: [IOError], tags: [ReadIOEffect], forbids: [].}
- Like lines(File) but also split each line into columns with Sep.