【问题标题】:Nim: work with read-only memory mapped filesNim:使用只读内存映射文件
【发布时间】:2021-02-02 17:22:29
【问题描述】:

我才刚开始接触 Nim,因此这可能是一个简单的问题。我们需要对存储在文件中的数据进行多次查找。其中一些文件太大而无法加载到内存中,因此采用 mmapped 方法。我可以通过 memfiles 对文件进行映射,并且我手边有一个指针或 MemSlice。文件和内存区域是只读的,因此具有固定大小。我希望我能够以不可变的固定大小字节和字符数组的形式访问数据而无需复制它们,利用所有现有的可用于 seq、数组、字符串等的功能。所有的 MemSlice /字符串方法复制数据,这是公平的,但不是我想要的(在我的用例中不需要)。

我了解数组、字符串等类型有一个指向数据的指针和一个 len 字段。但是找不到用指针和 len 创建它们的方法。我认为这与所有权有关,并且对 mem 的引用可能比我的切片寿命更长。

   let mm = memfiles.open(...)
   let myImmutableFixesSizeArr = ?? # cast[ptr array[fsize, char]](mm.mem) doesn't compile as fsize needs to be const. Neither could I find something like let x: [char] = array_from(mm.mem, fsize)
   let myImmutableFixedSizeString = mm[20, 30].to_fixed_size_immutable_string  # Create something that is string like so that I can use all the existing string methods.

更新:我确实找到了 https://forum.nim-lang.org/t/4680#29226,它解释了如何使用 OpenArray,但 OpenArray 只允许作为函数参数,而且你 - 如果我没记错的话 - 它的行为不像普通数组。

感谢您的帮助

【问题讨论】:

  • 您需要对这些字符串进行什么样的处理?它们是空终止的吗?

标签: nim-lang memmap


【解决方案1】:

无法将内存中的原始字符数组 (ptr UncheckedArray[char]) 转换为 string 而无需复制,只能转换为 openArray[char](或 cstring

因此,无法使用期望 string 的 proc,只能使用接受 openArray[T]openArray[char] 的 proc
令人高兴的是,openArray[T] 在发送到 proc 时的行为与 seq[T] 完全相同。

{.experimental:"views".} 确实允许您将 openArray[T] 分配给局部变量,但它还没有准备好用于生产)


您可以使用 memSlices 迭代器循环遍历 memFile 中的定界块而无需复制:

import memfiles

template toOpenArray(ms: MemSlice, T: typedesc = byte): openArray[T] =
  ##template because openArray isn't a valid return type yet
  toOpenArray(cast[ptr UncheckedArray[T]](ms.data),0,(ms.size div sizeof(T))-1)

func process(slice:openArray[char]) =
  ## your code here but e.g.
  ## count number of A's  
  var nA: int
  for ch in slice.items:
    if ch == 'A': inc nA
  debugEcho nA


let mm = memfiles.open("file.txt")
for slice in mm.memSlices:
  process slice.toOpenArray(char)


或者,要使用文件中间表示的某个字符数组,您可以使用指针算法。

import memfiles

template extractImpl(typ,pntr,offset) =
  cast[typ](cast[ByteAddress](pntr)+offset)

template checkFileLen(memfile,len,offset) =
  if offset + len > memfile.size:
    raise newException(IndexDefect,"file too short")

func extract*(mm: MemFile,T:typedesc, offset:Natural): ptr T =
  checkFileLen(mm,T,offset)
  result = extractImpl(ptr T,mm.mem,offset)
func extract*[U](mm: MemFile,T: typedesc[ptr U], offset: Natural): T = 
  extractImpl(T,mm.mem,offset)

let mm = memfiles.open("file.txt")

#to extract a compile-time known length string:
let mystring_offset = 3
const mystring_len = 10

type MyStringT = array[mystring_len,char]

let myString:ptr MyStringT = mm.extract(MyStringT,mystring_offset)
process myString[]

#to extract a dynamic length string:
let size_offset = 14
let string_offset = 18

let sz:ptr int32 = mm.extract(int32,size_offset)
let str:ptr UncheckedArray[char] = mm.extract(ptr UncheckedArray[char], string_offset)

checkFileLen(mm,sz[],string_offset)
process str.toOpenArray(0,sz[]-1)

【讨论】:

  • 感谢您的确认和示例。由于 OpenArray 上没有很多典型的 String 方法可用,我假设我必须创建或复制和粘贴我的应用程序所需的那些?
  • 根据以前的我,只需复制/粘贴作品:forum.nim-lang.org/t/6968#43685 并尝试 --gc:arc 以及
猜你喜欢
  • 2012-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 2021-02-08
  • 2013-02-17
相关资源
最近更新 更多