将内容添加到内存映射文件中。

28

我一直在向一个包含股票报价(整数、长整数、双浮点数等)的文件中不断追加内容。我使用mmap将此文件映射到内存中。

最有效的方法是什么,以使新追加的数据成为内存映射的一部分?

我知道我可以再次打开文件(新文件描述符),然后将其映射到获取新数据,但这似乎效率不高。有人建议我采用预分配1MB块的方法,写入特定位置,直到达到结尾,然后使用ftruncate将文件截断到+1MB。

还有其他方法吗?

Boost对此是否有帮助?

5个回答

27

Boost.IOStreams只能使用固定大小的内存映射文件,所以它对你的具体问题并没有帮助。Linux有一个接口mremap,其工作原理如下:

void *new_mapping = mremap(mapping, size, size + GROWTH, MREMAP_MAYMOVE);
if (new_mapping == MAP_FAILED)
    // handle error
mapping = new_mapping;

这种方法是非可移植的,而且文件中缺乏文档说明。Mac OS X 似乎没有 mremap

无论如何,您不需要重新打开文件,只需将其munmap,然后再次mmap即可:

void *append(int fd, char const *data, size_t nbytes, void *map, size_t &len)
{
    // TODO: check for errors here!
    ssize_t written = write(fd, data, nbytes);
    munmap(map, len);
    len += written;
    return mmap(NULL, len, PROT_READ, 0, fd, 0);
}

在这里使用预分配方案可能非常有用。一定要跟踪文件的实际长度,并在关闭之前再次截断它。


20

我知道答案已经被接受了,但如果我提供我的答案可能会帮助其他人。预先分配一个大文件,例如10 GiB的大小。提前创建三个这样的文件,我称之为卷。在某个地方(如标题、另一个文件等)跟踪您上次所在的位置,然后从那个点开始追加。如果您达到文件的最大大小并且没有剩余空间,请切换到下一个卷。如果没有更多的卷,请创建另一个卷。请注意,您可能会提前几个卷来执行此操作,以确保不会阻止追加等待创建新卷。这是我们在监控DVR系统中存储连续输入视频/音频的实现方式。我们不浪费空间为视频剪辑存储文件名,这就是为什么我们不使用真正的文件系统而使用平面文件,只需跟踪偏移量、帧信息(fps、帧类型、宽度/高度等)、录制时间和相机通道。对于您来说,存储空间很便宜,因为您正在进行的工作类型,而您的时间是无价的。因此,尽可能提前获取所需资源。您基本上正在为自己的需求优化自己的文件系统。通用文件系统提供的需求与其他领域的需求不同。


2

2
mremap是Linux特有的。 - Joel Reymont

1
我的意见是,这更适用于C语言。 创建普通文件,但使用mmap映射巨大的大小-例如,文件大小为100K,但mmap 1GB或更多。然后,您可以安全地访问文件大小内的所有内容。超出文件大小的访问将导致错误。如果您使用32位操作系统,请不要使mmap太大,因为它会占用您的地址空间。

-1
如果您在Windows上使用boost/iostreams/device/mapped_file.hpp
由于缺乏共享权限,boost::filesystem::resize_file会抛出异常,如果有一个读取映射对象是打开的。相反,使用Windows API来调整磁盘上的文件大小,这样读取mapped_file仍然可以保持打开状态。
bool resize_file_wapi(string path, __int64 new_file_size) //boost::uintmax_t size
{
    HANDLE handle = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL, 0);
    LARGE_INTEGER sz;
    sz.QuadPart = new_file_size;

    return handle != INVALID_HANDLE_VALUE
    && ::SetFilePointerEx(handle, sz, 0, FILE_BEGIN)
    && ::SetEndOfFile(handle)
    && ::CloseHandle(handle);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接