文件映射和文件结构

时间:2014-11-26 05:56:44

标签: c++ winapi

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

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

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

另一个问题。每次插入记录时都必须更新记录数。将指针移动到开头的正确方法是什么?同样的问题是用“prev”和“next”按钮移动指针。

提前谢谢。

更新 在这里,我尝试不创建一个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);

1 个答案:

答案 0 :(得分:1)

您可以同时在文件中拥有多个视图。因此,您可以只为count字段创建一个视图,并且每次都将新值写入同一个指针,然后创建另一个视图来读取/写入文件中的记录。

您已经知道如何使用指针算法来移动指针(尽管您在代码示例中没有正确执行)。为了简化操作,由于您的字段已修复,您应该定义一个包含记录所有字段的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);