代码之家  ›  专栏  ›  技术社区  ›  Dhyan Deep A.K

写入内存映射的文本文件打印空,直到映射内存结束

  •  -1
  • Dhyan Deep A.K  · 技术社区  · 7 年前

    在这段代码中,我将一些文本写入内存映射的文本文件。数据已成功写入文件,但当我用记事本打开文件时,在写入数据后,“NULL”会重复写入到映射内存限制,该限制大于我写入的文本。

    可能的原因是什么?

    pLogMsg = (char*)calloc(1024,sizeof(char));
    printf("[INFO] entering logger writeback thread\n");
    
    log_file = CreateFile (TEXT("one.txt"),             // Open one.txt.
                        GENERIC_READ | GENERIC_WRITE,   // Open for reading and writing
                        FILE_SHARE_WRITE,               // file share
                        NULL,                           // No security
                        OPEN_ALWAYS,                    // Open or create
                        FILE_ATTRIBUTE_NORMAL,          // Normal file
                        NULL);                          // No template file
    if (log_file == INVALID_HANDLE_VALUE)
    {
        printf("%d [ERR] cant open file GLE %d\n",GetCurrentThreadId(),GetLastError());
        return -1;
    }
    hMapping = CreateFileMapping( log_file, 0, PAGE_READWRITE, 0,4096 ,0 );
    if (hMapping == INVALID_HANDLE_VALUE)
    {
        printf("%d [ERR] cant create file mapping %d\n",GetCurrentThreadId(),GetLastError());
        return -1;
    }
    pFileData = (CHAR*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0,0, 0 );
    if (pFileData == NULL)
    {
        printf("%d [ERR] cant mapview of file %d\n",GetCurrentThreadId(),GetLastError());
        return -1;
    }
    pLogMsg = LogPrint();//returns a null terminated string
    memcpy(pFileData,pLogMsg,strlen(pLogMsg));
    pFileData += strlen(pLogMsg); 
    free(pLogMsg);
    
    3 回复  |  直到 7 年前
        1
  •  1
  •   RbMm    7 年前

    首先 CreateFileMapping MapViewOfFile 这对于日志文件来说是一个糟糕的解决方案。您需要使用创建/打开文件 FILE_APPEND_DATA 取而代之的是访问 GENERIC_READ | GENERIC_WRITE -所以通话必须是这样的:

    HANDLE log_file = CreateFileW(L"one.txt", 
        FILE_APPEND_DATA,
        FILE_SHARE_WRITE|FILE_SHARE_READ,     
        NULL,
        OPEN_ALWAYS,                 
        FILE_ATTRIBUTE_NORMAL,   
        NULL);
    

    在这种情况下,您可以使用 FILE\u APPEND\u数据 SYNCHRONIZE (因为没有 FILE_FLAG_OVERLAPPED ):

    如果调用方仅设置 FILE\u APPEND\u数据 使同步 旗帜,它 只能写入文件的末尾,以及任何偏移量信息 忽略对文件的关于写入操作。文件将 根据需要自动扩展此类型的操作。

    在此之后,您需要通过登录 WriteFile -它将自动附加到文件末尾。这正是日志文件所需要的。

    但是,如果想要使用 创建文件映射 到内存 -起初 创建文件映射 出错时返回0,请检查 if (hMapping == INVALID_HANDLE_VALUE) 是错误的

    如果您想更改文件大小,则需要使用 SetFileInformationByHandle 具有 FileEndOfFileInfo (vista+)或 NtSetInformationFile 具有 FileEndOfFileInformation (到处工作,怎么不难理解 SetFileInformationByHandle 只有很薄的外壳 NtSetInformationFile ZwSetInformationFile (在用户模式下,这是相同的功能)。使用 SetFilePointer 然后 SetEndOfFile 也有可能但不好且无效的选择-您将在src代码中有2个调用,而不是在单个上。在二进制中,您将遇到更糟糕的情况:首先设置文件位置,即 设置文件结束标志 NtSetInformationFile 用这个位置。因此,3次呼叫,而不是1次。并假设没有人在 SetFilePointer 设置文件结束标志 电话

    但需要清楚明白这一点 SetFileInformationByHandle 具有 FileEndOfFileInfo文件 只有在取消映射视图并关闭部分后,才能执行此操作。否则你会出错 ERROR_USER_MAPPED_FILE ( STATUS_USER_MAPPED_FILE )

    如果 创建文件映射 调用来为创建文件映射对象 hFile, UnmapViewOfFile 必须首先调用才能取消映射所有视图和 呼叫 闭合手柄 要关闭文件映射对象,请执行以下操作: 呼叫 设置文件结束标志 .

        2
  •  1
  •   Neil    7 年前

    文件中没有“文件结束”标记。您需要设置文件长度,以便操作系统正确标记它。

    有关详细信息,请参阅MSDN文档 SetEndOfFile

    Sets the physical file size for the specified file to the current position of the file pointer.

        3
  •  1
  •   IInspectable    7 年前

    不能通过文件映射设置文件结束标记。文件中实际上不存在文件结束标记。它是操作系统在读取超过文件末尾时发出的标志。

    要设置文件的大小,您必须调用 SetFilePointer 然后 SetEndOfFile 在用于创建文件映射的文件对象上。