2010-12-16 154 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); 
}