Reputation: 1148
I have a form with fixed-size fields. When a user enters data, it gets put into a file. There have to be "next" and "prev" buttons to navigate through the records.
My idea is to define a space for the count number in the beginning of the file, define amount of space for every record, and just insert data (shifting the pointer every time). Is it a good practice?
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
And another question. Every time a record inserted the number of records has to be updated. What is a correct way of shifting the pointer to the beginning? And the same question for shifting the pointer with "prev" and "next" buttons.
Thank you in advance.
Update
Here I try not to create a 10MB file, but instead to have it growing. I try to shift the view by sizeof(record) * (*pCount) + sizeof(DWORD)
, but obviously I'm missing something...
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);
Upvotes: 0
Views: 452
Reputation: 595320
You can have multiple views into a file at the same time. So you can create one view just for the count field and keep writing new values to the same pointer each time, then create another view for reading/writing records to the file.
You already know how to use pointer arithmetic to move a pointer around (though you are not doing ot correctly in your code example). To make things easier, since your fields are fixed, you should define a struct
that has all of the fields of a record, and then read/write entire struct
values at one time. That will also help you manage your pointer shifts, as you would simply add/subtract sizeof(the struct type)
number of bytes to your view pointer.
With that said, I would not suggest creating a 10MB view of the file. For one thing, it requires the file to be at least 10MB in size to begin with, even if it does not have 10MB worth of data in it, thus wasting disk space. You might want to re-think your mapping strategy so the file starts with just the initial counter and grows in size as new records are written. You would simply re-map the file when it grows, but you can still maintain a view that slides around the file's content by creating views at different offsets as needed (don't forget to take page boundaries onto account). Don't keep the entire file in a single view at all times since you are only accessing small sections at a time. It may be more convenient but it wastes more memory.
Try something like this:
#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);
Upvotes: 1