mmap:内存映射文件

楔子

建立一个文件的内存映射将使用操作系统虚拟内存来直接访问文件系统上的数据,而不是使用常规的I/O函数访问数据。 内存映射通常可以提高I/O性能,因为使用内存映射时,不需要对每一个访问都建立一个单独的系统调用,也不需要你在缓冲区之间复制数据。

实际上内核和用户应用都能直接访问内存。 内存映射文件可以看做是可修改的字符串或类似文件的对象,这取决于具体的需要。 映射文件支持一般文件的API方法,如close、flush、read、readline、seek、tell、write。而且还支持字符串的API,提供切片等特性以及类似find的方法 。

文件如下:

读文件

使用mmap函数可以创建一个内存映射文件。第一个参数是文件描述符,可以来自file对象的fileno方法,也可以来自os.open。

调用者在调用mmap方法之前负责打开文件,不再需要文件时要负责将其关闭。

mmap函数的第二个参数是要映射的文件部分的大小(以字节为单位)。如果这个值为0,则映射整个文件,如果这个大小大于文件的当前大小,则会扩展该文件。

import mmap

with open("1.txt", "r", encoding="utf-8") as f:
    '''
    有一个可选的参数access。使用ACCESS_READ表示只读访问;
    当然还有写,但是说实话,写的话不常用
    '''
    # 我们这里是读文件所以是mmap.ACCESS_READ
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
        print(m)  # <mmap.mmap object at 0x0000025FDA97A150>

直接打印的话,显示的是一个mmap.mmap对象,这个对象内部支持普通文件的一些api。

read方法:

import mmap

with open("1.txt", "r", encoding="utf-8") as f:
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
        # 调用m.read()得到文件内容,以字节的形式
        print(m.read().decode("utf-8"))
        """
        你怎么这么熟练啊!
        晨意微寒秋渐深,侧伴无事俏佳人
        为了我,你就永远当个废物吧;为了能让我好好努力,就一生,都成为我的负担吧。
        我喜欢这个世界上最糟糕的你,最喜欢了。
        第一次,有了喜欢的人,还得到了一生的挚友,两份喜悦相互重叠,这双重的喜悦又带来了更多更多的喜悦
        是我,是我先,明明都是我先来的,接吻也好,拥抱也好,还是喜欢上那家伙也好
        """
        # 由于读取完毕,所以再次读取得到的是空字节
        print(m.read())  # b''

readline方法:

import mmap

with open("1.txt", "r", encoding="utf-8") as f:
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
        # readline,按照行读取
        for _ in range(3):
            print(m.readline().decode("utf-8"))
            """
            你怎么这么熟练啊!

            晨意微寒秋渐深,侧伴无事俏佳人 

            为了我,你就永远当个废物吧;为了能让我好好努力,就一生,都成为我的负担吧。
            
            """
            # 由于有换行符,所以会有空行

size方法:

import mmap

with open("1.txt", "r", encoding="utf-8") as f:
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
        # 这个是查看文件的字节数,注意:是使用utf-8转换成字节所对应的字节数
        print(m.size())  # 499

当然也支持tell方法,表示当前文件指针所在的位置;以及seek,移动的文件的某个位置。

mmap.mmap对象最大的特点是支持像字符串一样访问数据,我们来看一下:

import mmap

with open("1.txt", "r", encoding="utf-8") as f:
    with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
        print(m.read(9).decode("utf-8"))  # 你怎么
        print(m[0: 9].decode("utf-8"))  # 你怎么
        print(m.read(9).decode("utf-8"))  # 这么熟

可以看到可以通过切片访问指定位置的内容,另外通过read访问也是可以的。通过read访问,会使得指针移动,但是切片无论何时都是从头读取,并且对文件指针的移动没有任何影响。

但是由于不同的字符占据不同的编码,比如汉字一个字符占三个字节,那么我们截取的时候要是3的整倍数。但如果是中英文混合的话,就比较尴尬了,所以这种方式比较适合纯ascii文本。

此外mmap.mmap对象还支持通过find和rfind定位指定字符所在的位置。

原文地址:https://www.cnblogs.com/traditional/p/11876345.html