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

时间:2017-12-05 10:40:18

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

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

答案 0 :(得分:1)

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

请参阅SetEndOfFile

的MSDN文档

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

答案 1 :(得分:1)

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

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

答案 2 :(得分: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_DATA SYNCHRONIZE 标志,那么   只能写入文件的末尾,以及任何偏移信息   关于对文件的写操作被忽略。该文件将   根据需要自动扩展此类操作。

之后你需要通过WriteFile登录 - 它会自动附加到文件末尾。这就是日志文件的确切需要。

但是,如果要使用CreateFileMappingMapViewOfFile - 首先CreateFileMapping错误时返回0,请检查 if (hMapping == INVALID_HANDLE_VALUE)错了

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

之间更改文件位置(在此句柄上)

但需要明确了解只有在取消映射视图和关闭部分之后才能使用SetEndOfFile调用SetFileInformationByHandle。否则你会收到错误FileEndOfFileInfoERROR_USER_MAPPED_FILE

  

如果调用 CreateFileMapping 来为其创建文件映射对象   首先必须调用hFile, UnmapViewOfFile 来取消所有视图的映射   调用 CloseHandle 来关闭文件映射对象,然后才能   致电 SetEndOfFile