【问题标题】:Writing to a memory mapped text file printing NULL till the end of mapped memory写入内存映射文本文件打印 NULL 直到映射内存结束
【发布时间】:2018-05-18 23:50:30
【问题描述】:

在这段代码中,我将一些文本写入内存映射文本文件。数据成功写入文件,但是当我用记事本打开它时,写入数据后,“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);

【问题讨论】:

  • 一般注释hMapping == INVALID_HANDLE_VALUE - 这是错误。 CreateFileMapping 失败返回 0

标签: c++ c winapi visual-c++


【解决方案1】:

首先CreateFileMappingMapViewOfFile 这是日志文件的错误解决方案。您需要使用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_APPEND_DATASYNCHRONIZE 打开文件(因为没有FILE_FLAG_OVERLAPPED):

如果调用者只设置 FILE_APPEND_DATASYNCHRONIZE 标志,它 只能写入文件末尾,以及任何偏移信息 关于文件的写操作被忽略。该文件将 为此类操作根据需要自动扩展。

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

然而,如果想使用CreateFileMappingMapViewOfFile - 首先CreateFileMapping 在错误时返回0,所以检查 if (hMapping == INVALID_HANDLE_VALUE)错了

如果你想改变文件大小 - 你需要使用 SetFileInformationByHandleFileEndOfFileInfo (vista+) 或 NtSetInformationFileFileEndOfFileInformation (在任何地方工作,如何不难理解 SetFileInformationByHandle 只是非常薄的外壳NtSetInformationFileZwSetInformationFile(在用户模式下这是相同的功能))。使用SetFilePointer 后跟SetEndOfFile 也是可能的,但这是不好且无效的选择 - 您将在 src 代码中进行 2 次调用,而不是单次调用。在二进制中 - 你会更糟糕的情况:首先你设置文件位置,SetEndOfFile 读取这个文件位置,最后用这个位置调用NtSetInformationFile。所以 3 个电话而不是 1 个。并假设没有人在 SetFilePointerSetEndOfFile 调用之间更改文件位置(在此句柄上)

但需要清楚地了解使用FileEndOfFileInfo 调用SetFileInformationByHandle 您只能在取消映射视图并关闭部分之后。否则你得到错误ERROR_USER_MAPPED_FILE (STATUS_USER_MAPPED_FILE)

如果调用 CreateFileMapping 来创建文件映射对象 hFile, UnmapViewOfFile 必须首先调用以取消映射所有视图和 调用 CloseHandle 关闭文件映射对象 调用 SetEndOfFile

【讨论】:

    【解决方案2】:

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

    请参阅 SetEndOfFile 的 MSDN 文档

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

    【讨论】:

    • SetFilePointer 可能也需要。
    • SetEndOfFile 写入后没有解决问题
    • @DhyanDeepA.K - 在尝试设置文件大小并获得 ERROR_USER_MAPPED_FILE 之前,您可能没有取消映射视图并关闭部分
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-23
      • 2016-01-08
      • 1970-01-01
      • 2012-02-08
      • 2010-12-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多