在mmap文件中删除/插入数据
我正在用Python写一个脚本,目的是通过mmap()来处理一个文件。
这个任务需要我对文件的内容进行以下几种操作:
- 替换数据
- 在文件的特定位置添加数据
- 从文件中删除数据(不是简单地把它涂掉)
替换数据的操作很顺利,只要旧数据和新数据的字节数相同就可以:
VDATA = mmap.mmap(f.fileno(),0)
start = 10
end = 20
VDATA[start:end] = "0123456789"
但是,当我尝试删除数据(用""替换某个范围)或者插入数据(用比原来范围更长的内容替换)时,我收到了一个错误信息:
IndexError: mmap slice assignment is wrong size
这个错误是可以理解的。
现在的问题是,我该如何在mmap映射的文件中插入和删除数据呢?从文档中看,似乎我可以通过一系列低级操作来移动文件的全部内容,但如果有更简单的解决方案,我更希望能避免这样做。
2 个回答
3
没有办法在不明确操作的情况下移动文件的内容,无论这个文件是通过内存映射(mmap)还是普通方式打开的。如果是内存映射的文件,你需要使用 mmap.move
这个方法来进行移动。
10
因为没有其他选择,我写了两个辅助函数 - deleteFromMmap() 和 insertIntoMmap() - 来处理一些底层的文件操作,这样可以让开发变得更简单。
关闭和重新打开 mmap,而不是使用 resize(),是因为在 Unix 系统上 Python 有个 bug,导致 resize() 不能正常工作。(http://mail.python.org/pipermail/python-bugs-list/2003-May/017446.html)
这些函数包含在一个完整的示例中。使用全局变量是因为主项目的格式这样要求,但你可以很容易地调整它,以符合你的编码标准。
import mmap
# f contains "0000111122223333444455556666777788889999"
f = open("data","r+")
VDATA = mmap.mmap(f.fileno(),0)
def deleteFromMmap(start,end):
global VDATA
length = end - start
size = len(VDATA)
newsize = size - length
VDATA.move(start,end,size-end)
VDATA.flush()
VDATA.close()
f.truncate(newsize)
VDATA = mmap.mmap(f.fileno(),0)
def insertIntoMmap(offset,data):
global VDATA
length = len(data)
size = len(VDATA)
newsize = size + length
VDATA.flush()
VDATA.close()
f.seek(size)
f.write("A"*length)
f.flush()
VDATA = mmap.mmap(f.fileno(),0)
VDATA.move(offset+length,offset,size-offset)
VDATA.seek(offset)
VDATA.write(data)
VDATA.flush()
deleteFromMmap(4,8)
# -> 000022223333444455556666777788889999
insertIntoMmap(4,"AAAA")
# -> 0000AAAA22223333444455556666777788889999