文件映射和文件结构

File-mapping and structure of file

本文关键字:文件结构 映射 文件      更新时间:2023-10-16

我有一个带有固定大小字段的表单。当用户输入数据时,它会被放入文件中。必须有"下一个"和"上一个"按钮才能浏览记录。

我的想法是为文件开头的计数定义一个空格,为每条记录定义空间量,然后插入数据(每次移动指针)。这是一种好的做法吗?

LPCTSTR pBuf = (LPTSTR)MapViewOfFile(fileMap, FILE_MAP_ALL_ACCESS, 0, 0, 10240000);
int charSize = sizeof(TCHAR);
...
memcpy((PVOID)pBuf, "0", charSize); //Record's count number when creating the file
...
memcpy((PVOID)pBuf, teacher, 31 * charSize); //the teacher field has length of 30
pBuf = pBuf + 31 * charSize; //shift the pointer
memcpy((PVOID)pBuf, discipline, 21 * charSize);
//and so on for other fields

还有一个问题。每次插入记录时,都必须更新记录数。将指针移动到开头的正确方法是什么?以及使用"上一个"和"下一个"按钮移动指针的相同问题。

提前谢谢你。

更新在这里,我尽量不创建一个 10MB 的文件,而是让它增长。我试图通过sizeof(record) * (*pCount) + sizeof(DWORD)来转移视图,但显然我错过了一些东西......

HANDLE fileMap = CreateFileMapping(fileHandle, NULL, PAGE_READWRITE, 0, sizeof(record) * ((*pCount) + 1) + sizeof(DWORD), NULL);
...
LPBYTE view = (LPBYTE)MapViewOfFile(fileMap, FILE_MAP_WRITE, 0, sizeof(record) * (*pCount) + sizeof(DWORD), sizeof(record)); 
...
record *pRecord = (record*)(view);

您可以同时将多个视图放入一个文件中。 因此,您可以仅为计数字段创建一个视图,并每次将新值写入同一指针,然后创建另一个视图以将记录读取/写入文件。

您已经知道如何使用指针算法来移动指针(尽管您在代码示例中没有正确执行 ot)。 为了简化操作,由于字段是固定的,因此应定义一个包含记录所有字段的struct,然后一次读取/写入整个struct值。这也将帮助您管理指针移位,因为您只需在视图指针中添加/减去sizeof(the struct type)字节数即可。

话虽如此,我不建议创建文件的 10MB 视图。 首先,它要求文件的大小至少为 10MB,即使它没有 10MB 的数据,从而浪费磁盘空间。 您可能需要重新考虑映射策略,以便文件仅从初始计数器开始,并随着新记录的写入而增加大小。 您只需在文件增长时重新映射文件,但您仍然可以根据需要创建不同偏移量的视图来维护围绕文件内容滑动的视图(不要忘记考虑页面边界)。不要始终将整个文件保存在单个视图中,因为您一次只能访问一小部分。它可能更方便,但它会浪费更多内存。

尝试这样的事情:

#pragma pack(push, 1)
struct record
{
    TCHAR teacher[31];
    TCHAR discipline[21];
    //and so on for other fields
};
#pragma pack(pop)
...
SYSTEM_INFO sysinfo
HANDLE fileMap;
LPDWORD countView;
LPBYTE currentView;
record* recordView;
...
GetSystemInfo(&sysinfo);
fileMap = CreateFileMapping(fileHandle, NULL, PAGE_READWRITE, 0, sizeof(DWORD), NULL);
countView = (LPDWORD) MapViewOfFile(fileMap, FILE_MAP_WRITE, 0, 0, sizeof(DWORD));
currentView = NULL;
recordView = NULL;
*countView = 0;
...
DWORD dwCount = *countView;
DWORD recordStart = sizeof(DWORD) + (dwCount * sizeof(record));
DWORD viewStart = (recordStart / sysinfo.dwAllocationGranularity) * sysinfo.dwAllocationGranularity;
DWORD viewSize = sizeof(record) + (recordStart % sysinfo.dwAllocationGranularity);
viewSize = (viewSize + (sysinfo.dwPageSize-1)) & ~(sysinfo.dwPageSize-1);
DWORD viewOffset = (recordStart - viewStart);
if (countView)
    UnmapViewOfFile(countView);
if (currentView)
    UnmapViewOfFile(currentView);
if (fileMap)
    CloseHandle(fileMap);
fileMap = CreateFileMapping(fileHandle, NULL, PAGE_READWRITE, 0, recordStart + sizeof(record), NULL);
countView = (LPDWORD) MapViewOfFile(fileMap, FILE_MAP_WRITE, 0, 0, sizeof(DWORD));
currentView = (LPBYTE) MapViewOfFile(fileMap, FILE_MAP_WRITE, 0, viewStart, viewSize); 
recordView = (record*) &currentView[viewOffset];
lstrcpyn(recordView->teacher, teacher, 31);
lstrcpyn(recordView->discipline, discipline, 21);
//and so on for other fields
++(*countView);