曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 4144|回复: 0
打印 上一主题 下一主题

RecordAccess 注释

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34397
跳转到指定楼层
楼主
发表于 2011-9-15 00:22:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
RecordAccess 来自 WSP4 ,它维护了一个记录尺寸固定的文件,该文件分为两个部分:文件头和文件内容。其中文件头包含了文件中的非空记录数以及文件记录容量,它用下面的结构表示:
[C++] 纯文本查看 复制代码
 struct _HEADER { 
    DWORD            numRecords;                /* 记录条数 */
    DWORD            numNonEmptyRecords;        /* 非空记录条数 */
} HEADER;


用户可以交互式的读,写(更新) 以及删除记录,每条记录包含时间戳,一个文本字符串和一个标识记录修改次数的计数值。

这个程序演示了将文件定位到某条记录的方法,并且展示了如何使用 Windows  LARGE_INTEGER 数据类型执行 64 位运算。

下面是程序代码并添加了注释:
[C++] 纯文本查看 复制代码
#include "stdafx.h"

#define    STRING_SIZE    256

/* 文件记录结构 */
typedef struct _RECORD {
    DWORD        referenceCount;        /* 该值为 0 时表示为空记录 */
    SYSTEMTIME        recordCreationTime;
    SYSTEMTIME        recordLastRefernceTime;
    SYSTEMTIME        recordUpdateTime;
    TCHAR            dataString[STRING_SIZE];
} RECORD;

/* 文件头部描述符 */
typedef struct _HEADER { 
    DWORD            numRecords;                /* 记录条数 */
    DWORD            numNonEmptyRecords;        /* 非空记录条数 */
} HEADER;
int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hFile;
    
    LARGE_INTEGER currentPtr;
    
    DWORD 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;

    int prompt = (argc <= 3) ? 1 : 0;

    if (argc < 2) {
        printf ("Usage: RecordAccess file [nrec [prompt]]\n");
        exit (1);
    }

    /* 如果 nrec > 2 则创建文件,同名原文件会被删除;否则打开文件*/
    OpenOption = ((argc > 2 && _ttoi(argv[2]) <= 0) || argc <= 2) ? OPEN_EXISTING : CREATE_ALWAYS;

    hFile = CreateFile (argv[1], GENERIC_READ | GENERIC_WRITE, 0, NULL, OpenOption, FILE_FLAG_RANDOM_ACCESS, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
            printf ("RecordAccess Error: Cannot open existing file.\n");
    
    if (argc >= 3 && _ttoi(argv[2]) > 0)  {

        if(!DeviceIoControl (hFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &nXfer, NULL))    /*将文件设置为稀疏文件*/
            printf ("RecordAccess Error: Making new file sparse.\n");
        
        header.numRecords = _ttoi(argv[2]);        /*命令行中给出记录条数*/

        if (!WriteFile(hFile, &header, sizeof (header), &nXfer, &ovZero))    /* 写入文件头 */
            printf ("RecordAccess Error: WriteFile header.\n");

        currentPtr.QuadPart = (LONGLONG)sizeof(RECORD) * _ttoi(argv[2]) + sizeof(HEADER);    /* 到文件末尾(文件头 + 记录信息) */

        if (!SetFilePointerEx (hFile, currentPtr, NULL, FILE_BEGIN))    /* 移动文件指针到文件尾 */
            printf("RecordAccess Error: Set Pointer.\n");

        if (!SetEndOfFile(hFile))        /* 设置文件末尾 */
            printf ("RecordAccess Error: Set End of File.\n");
    
        if (prompt)        /* 打印提示信息 */
            printf ("Empty file with %d records created.\n", header.numRecords);

        return 0;
    }

    /* 检查文件头以查看总的记录条数与非空记录条数 */
    if (!ReadFile(hFile, &header, sizeof (HEADER), &nXfer, &ovZero))
            printf("RecordAccess Error: ReadFile header.\n");

    if (prompt) 
        _tprintf (_T("File %s contains %d non-empty records of size %d.\n Total capacity: %d\n"),
            argv[1], header.numNonEmptyRecords, sizeof(RECORD), header.numRecords);

    while (TRUE) {
        headerChange = FALSE; recordChange = FALSE;

        /* 操作提示(读,写,删除,退出) */

        if (prompt) 
            printf ("Enter r(ead)/w(rite)/d(elete)/qu(it) record#\n");

        _tscanf (_T("%c%u%c"), &command, &recNo, &extra);

        if (command == _T('q')) 
            break;

        if (recNo >= header.numRecords) {        /* 指定的记录条数太大 */
            if (prompt) 
                printf ("record Number is too large. Try again.\n");
            continue;
        }
        currentPtr.QuadPart = (LONGLONG)recNo * sizeof(RECORD) + sizeof(HEADER);    /* 定位到指定的记录处 */

        ov.Offset = currentPtr.LowPart;            /* 重叠结构设置 */
        ov.OffsetHigh = currentPtr.HighPart;

        if (!ReadFile (hFile, &record, sizeof (RECORD), &nXfer, &ov))
                printf("RecordAccess: ReadFile failure.\n");

        GetSystemTime (&currentTime); /* 需要更新记录时间 */
        record.recordLastRefernceTime = currentTime;

        if (command == _T('r') || command == _T('d')) { 
            if (record.referenceCount == 0) {        /* 该标志表示记录是否为空,为0时表明记录此时已经为空 */
                if (prompt) 
                    printf ("record Number %d is empty.\n", recNo);
                continue;
            }else {
                    if (prompt) {
                        _tprintf (_T("record Number %d. Reference Count: %d \n"), recNo, record.referenceCount);
                        _tprintf (_T("Data: %s\n"), record.dataString);
                    }
                    
            }
            if (command == _T('d')) {            /* 删除记录 */
                record.referenceCount = 0;
                header.numNonEmptyRecords--;
                headerChange = TRUE;
                recordChange = TRUE;
            }
        } else if (command == _T('w')) {        /* 写记录 */
                if (prompt) 
                    printf ("Enter new data string for the record.\n");

                _fgetts (string, sizeof(string), stdin); /* 不要使用 _getts() 以防缓冲区溢出 */

                string[_tcslen(string)-1] = _T('\0'); /* 移除换行 */

                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 {
                if (prompt) 
                    printf ("command must be r, w, or d. Try again.\n");
            }

                if (recordChange && !WriteFile (hFile, &record, sizeof (RECORD), &nXfer, &ov))
                    printf("RecordAccess: WriteFile update failure.\n");

                if (headerChange) {
                    if (!WriteFile (hFile, &header, sizeof (header), &nXfer, &ovZero))
                        printf ("RecordAccess: WriteFile update failure.\n");
                }
    }

        if (prompt) 
            _tprintf (_T("Computed number of non-empty records is: %d\n"), header.numNonEmptyRecords);

        if (!ReadFile(hFile, &header, sizeof (HEADER), &nXfer, &ovZero))
            printf("RecordAccess Error: ReadFile header.\n");
    
        if (prompt) 
            _tprintf (_T("File %s NOW contains %d non-empty records.\nTotal capacity is: %d\n"),
                                argv[1], header.numNonEmptyRecords, header.numRecords);

        CloseHandle (hFile);
    return 0;
}

文件中的记录总数在命令行中指定。如果这个数很大,那么将会创建出一个非常巨型的文件为了避免占用大量的时间和磁盘空间,程序中使用 DeviceIoControl () 函数将文件设置为稀疏文件。稀疏文件在 XP 家庭版上不被支持,而在其它更高版本的 Windows 里都得到支持,所以这里直接用 DeviceIoControl() 将文件设置为稀疏文件,而无需利用 GetVolumeInformation() 函数先判断系统是否支持该文件类型。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-6-18 05:59 , Processed in 0.075847 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表