我不断地附加到一个股票报价文件(整数、多头、双精度等)。我用 mmap 将此文件映射到内存中。
使新附加的数据作为内存映射的一部分可用的最有效方法是什么?
我知道我可以再次打开文件(新文件描述符),然后对其进行映射以获取新数据,但这似乎效率低下。向我建议的另一种方法是将文件预先分配为 1mb 块,写入特定位置直到结束,然后将文件 ftruncate 到 +1mb。
还有其他方法吗?
Boost 对此有帮助吗?
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);
}
预分配方案在这里可能非常有用。确保跟踪文件的实际长度并在关闭之前再次截断它。
我知道答案已经被接受,但如果我提供我的答案,也许它会帮助其他人。提前分配一个大文件,比如 10 GiB 大小。提前创建其中三个文件,我称它们为卷。跟踪您最后一个已知位置,例如在标题、另一个文件等中,然后从该点继续追加。如果您达到文件的最大大小并且空间不足,请切换到下一卷。如果没有更多卷,请创建另一个卷。请注意,您可能会提前几个卷执行此操作,以确保不会阻塞等待创建新卷的追加。这就是我们在 DVR 系统中存储连续传入的视频/音频以进行监控的工作方式。我们不会浪费空间来存储视频剪辑的文件名,这就是我们不这样做的原因 t 使用真实的文件系统,而是使用平面文件,我们只跟踪偏移量、帧信息(fps、帧类型、宽度/高度等)、记录的时间和摄像机通道。对你来说,存储空间对于你正在做的工作来说很便宜,而你的时间是无价的。所以,尽可能多地抓住你想要的时间。您基本上是在实施针对您的需求优化的自己的文件系统。通用文件系统提供的需求与我们在其他领域的需求不同。重新实现您自己的针对您的需求优化的文件系统。通用文件系统提供的需求与我们在其他领域的需求不同。重新实现您自己的针对您的需求优化的文件系统。通用文件系统提供的需求与我们在其他领域的需求不同。
查看 mremap的手册页应该是可能的。
我的 5cents,但它们更特定于 C。制作普通文件,但 mmap 很大 - 例如文件说 100K,但 mmap 1GB 或更多。然后,您可以安全地访问文件大小的所有内容。访问超过文件大小将导致错误。如果您使用的是 32 位操作系统,请不要让 mmap 太大,因为它会占用您的地址空间。
如果您boost/iostreams/device/mapped_file.hpp
在 Windows 上使用:
boost::filesystem::resize_file
如果由于缺少共享权限而打开读取映射对象,则引发异常。而是使用windows-api调整光盘上的文件大小,读取mapped_file
s仍然可以打开。
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);
}