我尝试将文件从本地磁盘映射到内存,以便我的程序可以访问文件内容。当在文件上调用mmap(大小不到100kB)时,我从mmap返回的地址开始查看调试器中的内存,并且内存内容与文件内容不匹配(均以十六进制查看)。这是不字节交换问题。只有内存中的前2个字节与实际文件匹配,其余内容不匹配。
当我在包含字符串的小文件上重复相同的事情时(例如:" hello world"),那么在调试器中查看的内存与文件的内容完全匹配(再次以十六进制查看) )。
我尝试使用MAP_PRIVATE而不是MAP_SHARED但结果相同。如何才能使用我的大文件?
我在Ubuntu 17.10中使用Eclipse 4.7.2 + CDT并使用GDB进行调试。
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
void* MapAddr = NULL;
char* pData = NULL;
struct stat FileProps;
int FileDes = 0;
const char* fileNameAndPath = "/home/Test/testfile.txt";
FileDes = open(fileNameAndPath, O_RDWR);
if (FileDes != -1)
{
if (fstat(FileDes, &FileProps) == 0)
{
MapAddr = mmap(NULL, FileProps.st_size, (PROT_READ | PROT_WRITE), MAP_SHARED, FileDes, 0);
if (MapAddr == (void*) -1)
{
std::cout << "init: mmap failed" << std::endl;
return 0;
}
}
}
pData = (char*) MapAddr;
std::cout << pData << std::endl;
return 0;
}
13:10:42 ****构建配置调试项目mmapTest **** 做所有 构建文件:../ src / mmapTest.cpp 调用:GCC C ++编译器 g ++ -O0 -g3 -Wall -c -fmessage-length = 0 -MMD -MP -MF&#34; src / mmapTest.d&#34; -MT&#34; SRC / mmapTest.o&#34; -o&#34; src / mmapTest.o&#34; &#34; ../的src / mmapTest.cpp&#34; 完成建筑:../ src / mmapTest.cpp
构建目标:mmapTest
调用:GCC C ++链接器
g ++ -o&#34; mmapTest&#34; ./src/mmapTest.o
完成建筑目标:mmapTest
13:10:46构建完成(耗时4s.438ms)
答案 0 :(得分:1)
mmap()
实际上并没有将整个文件读入内存,也没有实际分配文件大小的RAM量。它只是分配足够大的虚拟地址空间来“适应”文件。
它通过使用页面错误来工作,当您尝试读取文件的某个区域时,将分配实际的RAM(或重新使用的其他页面)以及从文件读入内存的一定数量页面的数据。
你很难用mmap()
将整个文件加载到ram中。但是,无论何时尝试读取或写入数据(来自程序,不是来自调试器),您的程序都应该可以正常工作。
而且,是的,最重要的是,mmap()
的工作方式与CreateFileMapping()
的工作方式相同,因此您可以轻松移植代码。
答案 1 :(得分:0)
我确定了在运行mmap()之后,内存内容(在GDB调试器中查看)与实际文件内容不匹配的原因是我映射的文件不是ANSI编码的。所以调试器显示了正确的数据,正如Linux认为的那样。使用ANSI格式保存文件(在文本板中)后,在Linux中查看的文件的二进制内容与在Windows中查看的二进制内容相同。无需更改代码。问题在于映射文件。与其中一条评论相反,GDB调试器可以在mmap()返回的地址显示所有映射文件数据和内存查看器 - 我已经确认这个文件的数量高达100KB。