2010-12-16 118 views
21

我不断追加到股票报价文件(整数,长整数,双打等)。我用mmap将这个文件映射到内存中。追加到内存映射文件

将最新附加数据作为内存映射的一部分提供的最有效方式是什么?

据我所知,我可以再次打开文件(新文件描述符),然后将其映射到新的数据,但似乎效率低下。另一种建议给我的方法是以1mb的块预先分配文件,写入特定的位置直到达到结尾,然后将文件截断到+ 1mb。

还有其他方法吗?

Doest Boost对此有帮助吗?

回答

17

Boost.IOStreams固定大小只有memory mapped files,所以它不会帮助您的具体问题。 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); 
} 

预分配方案可能是非常有用的在这里。请务必跟踪文件的实际长度并在关闭之前再次截断它。

2

看着man page for mremap它应该是可能的。

+1

mremap是Linux专用的,但。 – 2010-12-16 15:16:13

14

我知道答案已被接受,但如果我提供答案,它可能会帮助其他人。提前分配一个大文件,例如10 GiB。提前创建其中三个文件,我称它们为卷。跟踪最后一个已知的位置,比如头文件,另一个文件等,然后从这一点开始追加。如果您达到文件的最大大小并将空间切换到下一个卷。如果没有更多卷,请创建另一个卷。请注意,您可能会提前完成几卷,以确保不会阻止附加内容等待创建新卷。这就是我们如何在DVR系统中存储连续传入的视频/音频进行监控的地方。我们不浪费空间来存储视频剪辑的文件名,这就是为什么我们不使用真正的文件系统,而是使用平面文件,我们只需跟踪偏移量,帧信息(帧数,帧类型,宽度/高度等) ),时间记录和相机频道。对于你来说,存储空间对于你正在做的工作来说便宜,而你的时间是非常宝贵的。所以,尽可能多地抓住你想要的时间。你基本上正在实现你自己的文件系统,以满足你的需求。通用文件系统提供的需求与我们在其他领域需要的需求并不相同。

0

我的5cents,但他们更具体的C。 制作普通文件,但是mmap尺寸很大 - 例如文件是100K,但是mmap 1GB或更多。然后,您可以安全地访问所有文件大小。通过文件大小访问将导致错误。 如果你在32位操作系统上,只是不要让mmap太大,因为它会占用你的地址空间。

0

如果你在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); 
}