我正在尝试使用以下代码将正则表达式应用于整个文件(而不仅仅是每行):
import mmap, re
ifile = open(ifilename)
data = mmap.mmap(ifile.fileno(), 0)
print data
mo = re.search('error: (.*)', data)
if mo:
print "found error"
这是基于问题How do I re.search or re.match on a whole file without reading it all into memory?
的答案但我收到以下错误:
Traceback (most recent call last):
File "./myscript.py", line 29, in ?
mo = re.search('error: (.*)', data)
File "/usr/lib/python2.3/sre.py", line 137, in search
return _compile(pattern, flags).search(string)
TypeError: expected string or buffer
如何解决此问题?
在问题Match multiline regex in file object中,我发现读取整个文件的另一种可能性是,而不是mmap对象:
data = open("data.txt").read()
有什么理由喜欢mmap
而不是简单的缓冲区/字符串?
答案 0 :(得分:7)
你真的有两个问题埋在这里。
如果升级到较新版本的Python,或者至少应该获得更好的追溯,那么您面临的问题很可能会得到解决。 mmap docs指定您需要打开文件进行更新以对其进行mmap,并且您当前没有这样做。
ifile = open(ifilename) # default is to open as read
应该是这样的:
ifile = open(ifilename, 'r+')
或者,如果您可以像评论中提到的那样更新到Python 2.6,
with open(ifilename, 'r+') as fi:
# do stuff with open file
如果您没有在2.7上打开具有写入权限的文件并尝试对其进行mmap,那么" Permission denied"提出异常。我怀疑2.3中没有实现错误,所以现在你被允许继续使用无效的mmap对象,当你尝试用正则表达式进行搜索时它会失败。
最后,你可以用两种方法(几乎)做同样的事情。 re.search(pattern, mmap_or_long_string)
将搜索您的内存映射文件或read()
调用产生的长字符串。
两种方法的主要区别在于虚拟与实内存消耗。
在内存映射文件中,文件保留在磁盘上(或任何位置),您可以通过虚拟内存地址直接访问它。当您使用read()
读取文件时,您将整个文件一次性存入(实际)内存。
为什么选择其中一个:
文件大小
您可以映射的文件大小的最重要限制是虚拟内存地址空间的大小,这由CPU(32位或64位)决定。分配的内存必须是连续的,因此如果操作系统无法找到足够大的块来分配内存,则可能会出现分配错误。另一方面,使用read()
时,您的限制是可用的物理内存。如果您访问的文件大于可用内存并且读取单行不是一个选项,请考虑使用mmap。
进程间的文件共享
如果要在大文件上并行化只读操作,则可以将其映射到内存中以在进程之间共享它,而不是在整个文件的副本中读取每个进程。
可读性/熟悉
与内存映射相比,更多人熟悉简单的open()
和read()
函数。除非你有令人信服的理由使用mmap,否则从长远来看,坚持使用基本IO功能可能更好。
速度
这个是洗。很多论坛和帖子都喜欢谈论mmap速度(因为一旦文件被映射就会绕过一些系统调用),但底层机制仍在访问磁盘,而读取整个文件会将所有内容带入内存而只执行磁盘在使用该文件的开始和结束时访问。如果您尝试考虑缓存(包括硬盘和CPU),内存分页和文件访问模式,则会有无穷无尽的复杂性。坚持使用经过验证的真实剖析方法要容易得多。您将根据您的个人用例和文件的访问模式查看不同的结果,因此对两者进行分析并查看哪一个更快。
A good summary of the differences
PyMOTW
A good SO question
Wikipedia Virtual Memory article