C++ 文件映射和文件结构
我有一个固定大小字段的表单。当用户输入数据时,它会被放入一个文件中。必须有“下一步”和“上一步”按钮才能浏览记录 我的想法是在文件的开头为count number定义一个空间,为每个记录定义一个空间量,然后插入数据(每次移动指针)。这是一种好的做法吗C++ 文件映射和文件结构,c++,winapi,C++,Winapi,我有一个固定大小字段的表单。当用户输入数据时,它会被放入一个文件中。必须有“下一步”和“上一步”按钮才能浏览记录 我的想法是在文件的开头为count number定义一个空间,为每个记录定义一个空间量,然后插入数据(每次移动指针)。这是一种好的做法吗 LPCTSTR pBuf = (LPTSTR)MapViewOfFile(fileMap, FILE_MAP_ALL_ACCESS, 0, 0, 10240000); int charSize = sizeof(TCHAR); ... memcpy
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);
一个文件中可以同时有多个视图。因此,您可以仅为count字段创建一个视图,并保持每次向同一指针写入新值,然后创建另一个视图,用于读取/写入文件中的记录 您已经知道如何使用指针算术来移动指针(尽管您在代码示例中没有正确执行ot)。为了简化操作,因为字段是固定的,所以应该定义一个包含记录所有字段的
struct
,然后一次读取/写入整个struct
值。这也将帮助您管理指针移位,因为您只需向视图指针添加/减去sizeof(结构类型)
字节数
尽管如此,我不建议创建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*) ¤tView[viewOffset];
lstrcpyn(recordView->teacher, teacher, 31);
lstrcpyn(recordView->discipline, discipline, 21);
//and so on for other fields
++(*countView);
如果你在C++中使用MeMCPY,你认为你的设计是否可以?为什么不使用obejcts呢?条目&列表和文件中的表示形式。我从你剪下的头发上看到的看起来很难看!我知道这很难看,这就是为什么我问这个问题,我只是WinApi的初学者。谢谢你提出使用条目和列表的建议,我会试试的。非常感谢你的回答,雷米。我开始执行你说的。我没有创建一个10MB的文件,但是每次都将它放大一个sizeof(record)+sizeof(DWORD)。我试图每次只为下一条记录创建一个视图。这是我的代码:
handlefilemap=CreateFileMapping(fileHandle,NULL,PAGE\u READWRITE,0,sizeof(record)*((*pCount)+1)+sizeof(DWORD),NULL);LPBYTE视图=(LPBYTE)映射视图文件(文件映射,文件映射,写入,0,大小(记录)*(*pCount)+大小(DWORD),大小(记录));记录*pRecord=(记录*)(视图)代码>它不工作。我遗漏了什么?你没有考虑页面边界。我警告过你。视图必须以系统粒度的偶数倍开始,不能以任意偏移量开始。这在MapViewOfFile()
文档中有明确说明。我在映射代码中所做的是获取所需的文件偏移量,并将其向下舍入到最近的页面边界,创建视图,并计算所需视图开始和实际视图开始之间的偏移量,以便我可以跳过这些字节,然后访问视图的数据。此外,当创建新的文件映射时,例如当文件大小发生变化时,您还必须取消映射并创建一个新的pCount
视图,因为您必须关闭支持它的上一个文件映射。