Windows System Programming Third Edition [Electronic resources]

Johnson M. Hart

نسخه متنی -صفحه : 291/ 47
نمايش فراداده

  • Example: Random Record Updates

    Chapter 14 on the Web site, although not in the text) also illustrates direct file access.

    Program 3-1. RecordAccess
    /* Chapter 3. RecordAccess. */
    /* Usage: RecordAccess FileName [nrec]
    If nrec is omitted, FileName must already exist.
    If nrec is supplied, create FileName (destroying an existing file).
    If the number of records is large, a sparse file is recommended. */
    /* This program illustrates:
    1. Random file access.
    2. LARGE_INTEGER arithmetic and using the 64-bit file positions.
    3. Record update in place.
    4. File initialization to 0 (requires an NTFS file system).
    */
    #include "EvryThng.h"
    #define STRING_SIZE 256
    typedef struct _RECORD { /* File record structure */
    DWORD         ReferenceCount;  /* 0 means an empty record. */
    SYSTEMTIME    RecordCreationTime;
    SYSTEMTIME    RecordLastReferenceTime;
    SYSTEMTIME    RecordUpdateTime;
    TCHAR         DataString[STRING_SIZE];
    } RECORD;
    typedef struct _HEADER { /* File header descriptor */
    DWORD      NumRecords;
    DWORD      NumNonEmptyRecords;
    } HEADER;
    int _tmain (int argc, LPTSTR argv [])
    {
    HANDLE hFile;
    LARGE_INTEGER CurPtr;
    DWORD FPos, OpenOption, nXfer, RecNo;
    RECORD Record;
    TCHAR String[STRING_SIZE], Command, Extra;
    OVERLAPPED ov = {0, 0, 0, 0, NULL}, ovZero = {0, 0, 0, 0, NULL};
    HEADER Header = {0, 0};
    SYSTEMTIME CurrentTime;
    BOOLEAN HeaderChange, RecordChange;
    OpenOption = (argc == 2) ? OPEN_EXISTING : CREATE_ALWAYS;
    hFile = CreateFile (argv [1], GENERIC_READ | GENERIC_WRITE,
    0, NULL, OpenOption, FILE_ATTRIBUTE_NORMAL, NULL);
    if (argc >= 3)  { /* Write the header and presize the new file) */
    Header.NumRecords = atoi(argv[2]);
    WriteFile(hFile, &Header, sizeof (Header), &nXfer, &ovZero);
    CurPtr.QuadPart = sizeof(RECORD)*atoi(argv[2])+sizeof(HEADER);
    FPos =       SetFilePointer (hFile, CurPtr.LowPart,
    &CurPtr.HighPart, FILE_BEGIN);
    if (FPos == 0xFFFFFFFF && GetLastError () != NO_ERROR)
    ReportError (_T ("Set Pointer error."), 4, TRUE);
    SetEndOfFile(hFile);
    }
    /* Read file header: find number of records & nonempty records. */
    ReadFile(hFile, &Header, sizeof (HEADER), &nXfer, &ovZero);
    /* Prompt the user to read or write a numbered record. */
    while (TRUE) {
    HeaderChange = FALSE; RecordChange = FALSE;
    _tprintf (_T("Enter r(ead)/w(rite)/d(elete)/q Record#\n"));
    _tscanf (_T ("%c" "%d" "%c"), &Command, &RecNo, &Extra );
    if (Command == 'q') break;
    CurPtr.QuadPart = RecNo * sizeof(RECORD) + sizeof(HEADER);
    ov.Offset = CurPtr.LowPart;
    ov.OffsetHigh = CurPtr.HighPart;
    ReadFile (hFile, &Record, sizeof (RECORD), &nXfer, &ov);
    GetSystemTime (&CurrentTime); /* To update record time fields */
    Record.RecordLastRefernceTime = CurrentTime;
    if (Command == 'r' || Command == 'd') { /* Report contents. */
    if (Record.ReferenceCount == 0) {
    _tprintf (_T("Record Number %d is empty.\n"), RecNo);
    continue;
    } else {
    _tprintf (_T("Record Number %d. Reference Count: %d \n"),
    RecNo, Record.ReferenceCount);
    _tprintf (_T("Data: %s\n"), Record.DataString);
    /* Exercise: Display times. See next example. */
    RecordChange = TRUE;
    }
    if (Command == 'd') { /* Delete the record. */
    Record.ReferenceCount = 0;
    Header.NumNonEmptyRecords--;
    HeaderChange = TRUE;
    RecordChange = TRUE;
    }
    } else if (Command == 'w') { /* Write the record. First time? */
    _tprintf (_T("Enter new data string for the record.\n"));
    _getts (String);
    if (Record.ReferenceCount == 0) {
    Record.RecordCreationTime = CurrentTime;
    Header.NumNonEmptyRecords++;
    HeaderChange = TRUE;
    }
    Record.RecordUpdateTime = CurrentTime;
    Record.ReferenceCount++;
    _tcsncpy (Record.DataString, String, STRING_SIZE-1);
    RecordChange = TRUE;
    } else {
    _tprintf (_T("Command must be r, w, or d. Try again.\n"));
    }
    /* Update record in place if any contents have changed. */
    if (RecordChange)
    WriteFile (hFile, &Record, sizeof (RECORD), &nXfer, &ov);
    /* Update the number of nonempty records if required. */
    if (HeaderChange)
    WriteFile(hFile, &Header, sizeof (Header), &nXfer, &ovZero);
    }
    _tprintf (_T("Computed number of nonempty records is: %d\n"),
    Header.NumNonEmptyRecords);
    CloseHandle (hFile);
    return 0;
    }