使用mmap映射后,文件中的'\n'变成了'\r\n'
2011-11-08 23:28
288 查看
关于mmap,《Python v2.7.2 documentation》中的描述如下:
mmap — Memory-mapped file support
Memory-mapped file objects behave like both strings and like file objects. Unlike normal string objects, however, these are mutable. You can use mmap objects in most places where strings are expected; for example, you can use the re module to search through a memory-mapped file. Since they’re mutable, you can change a single character by doing obj[index] = 'a', or change a substring by assigning to a slice: obj[i1:i2] = '...'. You can also read and write data starting at the current file position, and seek() through the file to different positions.
在re+mmap实现大文件的正则匹配中,我采取“首先用mmap映射文件,然后用re匹配内容”的方法进行过大文件的正则匹配。这种方法确实有效。但是,当我将使用正则表达式从映射文件中提取到的匹配结果写入新文件时,用Vim打开新文件后,每一行的结尾处总有一个^M字符(0x0d)。当时觉得有点奇怪,不过想了想又以为可能是正则匹配的中间信息没有被删除掉,当时也不影响后续的文件操作,所以也没有继续研究。
最近因为要分析C程序中的宏的缘故,再次用到了re+mmap组合。待分析的头文件data.h的内容为:
#define LEN 2\n
按照逻辑,我编写了如下正则表达式用于匹配提取宏名及其对应的替换文本:
macro_regex = re.compile(r"\s*#\s*define\s*(\w+)\s*(.*?)[\n]")
以下代码中,分别使用macro_regex直接匹配文件内容,以及匹配mmap映射后的文件内容:
所得的结果输出为:
上述结果表明:mmap映射后的文件内容发生了变化。于是,我又直接比较了data.h的原始文件内容和mmap映射后的文件内容:
#define LEN 2\n ## 原始文件内容
#define LEN 2\r\n ## mmap映射后的文件内容
果然,mmap映射后的文件内容中,原来的'\n'变成了'\r\n'。我这才发现,原来之前Vim打开时看到的每行末尾的^M字符(0x0d)其实就是'\r'。我后来又做了一系列的测试(比如将mmap映射后的文件内容直接写入到另一个文件中),证实了确实存在这种差异。
“ 使用mmap映射后,文件中的'\n'变成了'\r\n' ”
这种差异非常隐晦,一般情况下很难预料;但这种差异的影响却显而易见:如果使用mmap映射后的文件内容已经发生了变化,那么以原始的文件内容为依据的所有假设和逻辑都可能会出现混乱。
值得一提的是,这种情况是我在Windows下面使用Python2.7时遇到的,其他系统平台和Python版本下的情况我没有验证过。在此做一个记录,以备后续回顾与参考。
mmap — Memory-mapped file support
Memory-mapped file objects behave like both strings and like file objects. Unlike normal string objects, however, these are mutable. You can use mmap objects in most places where strings are expected; for example, you can use the re module to search through a memory-mapped file. Since they’re mutable, you can change a single character by doing obj[index] = 'a', or change a substring by assigning to a slice: obj[i1:i2] = '...'. You can also read and write data starting at the current file position, and seek() through the file to different positions.
在re+mmap实现大文件的正则匹配中,我采取“首先用mmap映射文件,然后用re匹配内容”的方法进行过大文件的正则匹配。这种方法确实有效。但是,当我将使用正则表达式从映射文件中提取到的匹配结果写入新文件时,用Vim打开新文件后,每一行的结尾处总有一个^M字符(0x0d)。当时觉得有点奇怪,不过想了想又以为可能是正则匹配的中间信息没有被删除掉,当时也不影响后续的文件操作,所以也没有继续研究。
最近因为要分析C程序中的宏的缘故,再次用到了re+mmap组合。待分析的头文件data.h的内容为:
#define LEN 2\n
按照逻辑,我编写了如下正则表达式用于匹配提取宏名及其对应的替换文本:
macro_regex = re.compile(r"\s*#\s*define\s*(\w+)\s*(.*?)[\n]")
以下代码中,分别使用macro_regex直接匹配文件内容,以及匹配mmap映射后的文件内容:
f = open('data.h', 'r') # 直接匹配文件内容 data = f.read() print macro_regex.findall(data) # 匹配mmap映射后的文件内容 data = mmap.mmap(f.fileno(), 0, access = mmap.ACCESS_READ) print macro_regex.findall(data) f.close()
所得的结果输出为:
[('LEN', '2')] [('LEN', '2\r')]
上述结果表明:mmap映射后的文件内容发生了变化。于是,我又直接比较了data.h的原始文件内容和mmap映射后的文件内容:
#define LEN 2\n ## 原始文件内容
#define LEN 2\r\n ## mmap映射后的文件内容
果然,mmap映射后的文件内容中,原来的'\n'变成了'\r\n'。我这才发现,原来之前Vim打开时看到的每行末尾的^M字符(0x0d)其实就是'\r'。我后来又做了一系列的测试(比如将mmap映射后的文件内容直接写入到另一个文件中),证实了确实存在这种差异。
“ 使用mmap映射后,文件中的'\n'变成了'\r\n' ”
这种差异非常隐晦,一般情况下很难预料;但这种差异的影响却显而易见:如果使用mmap映射后的文件内容已经发生了变化,那么以原始的文件内容为依据的所有假设和逻辑都可能会出现混乱。
值得一提的是,这种情况是我在Windows下面使用Python2.7时遇到的,其他系统平台和Python版本下的情况我没有验证过。在此做一个记录,以备后续回顾与参考。
相关文章推荐
- 使用mmap即文件映射实现文件的快速复制
- 使用mmap实现文件映射
- 文件映射mmap简单设置文件大小(lseek (ftruncate可以设置文件大小))__使用mmap即文件映射实现文件的快速复制代码
- 【C语言】【unix c】使用mmap将文件映射到进程的虚拟地址空间,然后对内存的操作直接反应到文件中
- 使用存储映射I/O函数mmap进行文件拷贝
- mmap的使用之两个进程通过映射普通文件实现共享内存通信
- mmap映射文件至内存( 实现 共享内存 与 文件的另类访问 )
- 内存映射对于大文件的使用
- 使用hbm2java根据映射文件生成POJO
- 对一个文件使用内存映射文件
- 使用oracle数据库和MySQL数据库时hibernate的映射文件.hbm.xml的不同
- 使用文件映射的方式进行共享数据中CreateFileMapping、MapViewOfFile函数参数说明
- VC++中使用内存映射文件处理大文件
- mmap的使用及pcap文件解析示例
- Mongodb源码分析--内存文件映射(MMAP)
- 使用内存映射文件在进程间共享数据
- Spring使用通配符自动加载hibernate映射文件生成sessionFactory
- MyBatis框架核心之(二)Mapper配置文件使用接口映射
- 对使用"ALTER DATABASE BACKUP CONTROLFILE TO ''" 备份的控制文件的恢
- SSM框架之Mybatis SQL映射文件基本使用