2008-10-12 51 views
2

我正在編寫大型檔案文件(見下文)的4GB +,原生&託管C++。設計:大檔案文件編輯器,文件映射

對於訪問文件,我使用文件映射(見下文)像任何理智的人。這對於讀取數據非常有用,但是在實際編輯存檔時會出現問題。 文件映射不允許在文件被訪問時調整文件大小,所以我不知道當用戶想要在文件中插入新數據時該如何繼續(當文件被映射時,這會超過文件的原始大小)。

我應該每次重新映射整個事物嗎?這肯定會很慢。但是,我想讓編輯實時訪問專有文件,因爲這樣可以大大簡化編程,並且不會讓文件在修改時被其他應用程序搞亂。我不想花時間去編輯這個編輯;這只是我正在開發的實際項目的簡單開發工具。

所以我想聽聽你是如何處理類似的情況,以及其他歸檔軟件,尤其是其他遊戲如何解決這個問題?

澄清:

  • 這是不是一個文本文件,我正在寫一個特定的二進制檔案文件格式。我的意思是一個包含許多其他目錄的大文件。自定義歸檔文件在遊戲使用中非常常見,原因很多。以我的格式,我的目標是與Valve Software's GCF format類似(但更簡單)的結構 - 我會盡可能使用GCF格式,但不幸的是沒有格式的編輯器,儘管有很多好的實現來讀取它們,如HLLib

  • 訪問文件必須快速,因爲它旨在用於存儲遊戲資源。所以這不是一個數據庫。數據庫文件將包含在其中,以及GFX,SFX等文件。

  • 這裏討論的「文件映射」是Windows平臺上的一項特定技術,它允許通過爲其部分創建「視圖」來直接訪問大文件,請參見:http://msdn.microsoft.com/en-us/library/aa366556(VS.85).aspx - 此技術允許最小延遲和內存使用情況,並且是訪問任何大型文件的理由。 所以這是而不是意味着將整個4GB文件讀入內存,這完全相反。

回答

1

我所做的是關閉視圖句柄和FileMapping句柄,設置文件大小,然後重新打開映射/視圖句柄。

// Open memory mapped file  
HANDLE FileHandle = ::CreateFileW(file_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 
size_t Size = ::GetFileSize(FileHandle, 0); 
HANDLE MappingHandle = ::CreateFileMapping(FileHandle, NULL, PAGE_READWRITE, 0, Size, NULL); 
void* ViewHandle = ::MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, Size); 

... 

// increase size of file 
UnmapViewOfFile(ViewHandle); 
CloseHandle(MappingHandle); 

Size += 1024; 


LARGE_INTEGER offset; 
offset.QuadPart = Size; 

LARGE_INTEGER newpos; 
SetFilePointerEx(FileHandle, offset, &newpos, FILE_BEGIN); 
SetEndOfFile(FileHandle); 

MappingHandle = ::CreateFileMapping(FileHandle, NULL, PAGE_READWRITE, 0, Size, NULL); 
ViewHandle = ::MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, Size); 

上面的代碼沒有錯誤檢查和不處理64位的大小,但是這並不難解決。

+0

是的,這正是我想我必須做的。另一件事是優化空間開銷的速度:我想第一次爲文件保留一大塊空間,並在關閉文件時將其大小調整爲真正的EOF。 – anon6439 2008-10-13 05:16:54

2

「編輯軟件」是什麼意思?如果這是一個文本文件,是否在編寫自己的文件之前嘗試過現有的生產質量編輯器?如果它是一個存儲二進制數據的文件,是否考慮過使用RDBMS並使用SQL語句操作其內容?

如果您絕對必須從頭開始編寫此代碼,我不確定該映射是否可行。映射一個巨大的文件會給你的機器的虛擬機系統帶來很大的壓力,除非整個文件有很多編輯操作,否則它的效率可能會落後於一個簡單的讀/寫方案。更糟的是,如你所說,當你想擴展文件時,你遇到了問題。

取而代之的是,將緩衝區窗口保存到用戶可以修改的文件數據中。當用戶決定保存文件時,順序遍歷文件和編輯的緩衝區以創建新的文件映像。如果你有磁盤空間,寫一個新文件比較容易(尤其是如果緩衝區的大小已經改變),否則你需要聰明地閱讀現有數據,然後用新內容覆蓋它。

或者,您可以保留一個編輯操作日誌。當用戶決定保存文件時,對日誌執行拓撲排序並在現有文件上播放以創建新文件。

對於獨佔文件訪問使用操作系統的文件鎖定或實現應用程序級鎖定(如果只有您的編輯器將觸摸這些文件)。取決於mmap獨佔訪問限制您的實施選擇。

2

映射文件是爲實際訪問數據創建的,但我認爲您需要另一個表示文件結構的抽象。有多種方式可以做到這一點,但可以考慮將文件表示爲一系列'範圍'。

從文件開始是一個等同於整個映射的範圍。如果用戶開始編輯文件,則可以在編輯點處將單個盤區分成兩部分,然後插入一個包含用戶插入數據的新盤區。修改和刪除也會通過創建或修改這些範圍來修改您的文件視圖。

也許你可以檢查其中一個開源編輯器的源代碼 - 有很多選擇,但找到一個足夠簡單的將是挑戰。

+0

嗨 - 是的,正好 - 我的問題是保持簡單。我仍然希望有辦法做到這一點,而不必跟蹤「虛擬」變化,並在稍後分開沖洗,但不幸的是,這看起來似乎是唯一可行的選擇。 – anon6439 2008-10-12 18:10:36

1

這個問題沒有簡單的答案 - 我找了很久很久沒有找到答案。您必須修改文件的大小,然後重新映射它。

1

映射對遠程系統上的文件存在基本問題。

在DOS很好的日子裏,出現了一個名爲Norton Editor的好編輯器(ne.com ..這是 文件名,而不是網站)。它可以加載任何大小的文件(我們正在談論640kb RAM 和20 GB硬盤,如果有的話)。

它用來加載文件中的一部分,巧妙地管理文件長的搜索點播 裝載

恕我直言,應該使用這種方法。

如果在文件讀寫層下正確隱藏,它可能會令人驚訝地透明。

0

我會在構建時從碎片構建大文件。你的編輯器處理普通的平面文件,在通常的文件系統中(在適當的情況下有子目錄等)。然後,您有一個編譯步驟,將所有這些部分一起收集到您的存檔文件文件格式中。