25

我不断地附加到一个股票报价文件(整数、多头、双精度等)。我用 mmap 将此文件映射到内存中。

使新附加的数据作为内存映射的一部分可用的最有效方法是什么?

我知道我可以再次打开文件(新文件描述符),然后对其进行映射以获取新数据,但这似乎效率低下。向我建议的另一种方法是将文件预先分配为 1mb 块,写入特定位置直到结束,然后将文件 ftruncate 到 +1mb。

还有其他方法吗?

Boost 对此有帮助吗?

4

5 回答 5

26

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.

在任何情况下,您都不需要重新打开文件,只需重新打开munmapmmap

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);
}

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

于 2010-12-16T13:54:45.530 回答
18

我知道答案已经被接受,但如果我提供我的答案,也许它会帮助其他人。提前分配一个大文件,比如 10 GiB 大小。提前创建其中三个文件,我称它们为卷。跟踪您最后一个已知位置,例如在标题、另一个文件等中,然后从该点继续追加。如果您达到文件的最大大小并且空间不足,请切换到下一卷。如果没有更多卷,请创建另一个卷。请注意,您可能会提前几个卷执行此操作,以确保不会阻塞等待创建新卷的追加。这就是我们在 DVR 系统中存储连续传入的视频/音频以进行监控的工作方式。我们不会浪费空间来存储视频剪辑的文件名,这就是我们不这样做的原因 t 使用真实的文件系统,而是使用平面文件,我们只跟踪偏移量、帧信息(fps、帧类型、宽度/高度等)、记录的时间和摄像机通道。对你来说,存储空间对于你正在做的工作来说很便宜,而你的时间是无价的。所以,尽可能多地抓住你想要的时间。您基本上是在实施针对您的需求优化的自己的文件系统。通用文件系统提供的需求与我们在其他领域的需求不同。重新实现您自己的针对您的需求优化的文件系统。通用文件系统提供的需求与我们在其他领域的需求不同。重新实现您自己的针对您的需求优化的文件系统。通用文件系统提供的需求与我们在其他领域的需求不同。

于 2012-08-19T03:06:33.670 回答
2

查看 mremap的手册页应该是可能的。

于 2010-12-16T12:20:07.427 回答
1

我的 5cents,但它们更特定于 C。制作普通文件,但 mmap 很大 - 例如文件说 100K,但 mmap 1GB 或更多。然后,您可以安全地访问文件大小的所有内容。访问超过文件大小将导致错误。如果您使用的是 32 位操作系统,请不要让 mmap 太大,因为它会占用您的地址空间。

于 2015-01-05T21:16:41.243 回答
-1

如果您boost/iostreams/device/mapped_file.hpp在 Windows 上使用:

boost::filesystem::resize_file如果由于缺少共享权限而打开读取映射对象,则引发异常。而是使用windows-api调整光盘上的文件大小,读取mapped_files仍然可以打开。

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);
}
于 2016-11-17T15:43:12.997 回答