C ++从磁盘读取文件并将其写入共享内存

时间:2018-05-06 10:11:29

标签: c++ winapi shared-memory lptstr

我的目标是实现以下目标:

我想从磁盘读取文件(假设它是一个图像文件)并将其写入共享内存,以便我可以从另一个进程的共享内存中读取它。 首先,我跟着this msdn tutorial创建了一个包含字符串的简单共享内存实现。它工作正常。

然后我找到了一种从磁盘读取图像的方法。实施如下:

std::ifstream fin("path/to/img.png", std::ios::in | std::ios::binary);
std::ostringstream oss;
oss << fin.rdbuf();
std::string data(oss.str());

现在我有一个std::string包含我的数据data.length()表示我读过的文件已成功存储在那里。在msdn示例中,MapViewOfFile结果的类型为LPTSTR,因此我找到了一种方法来投射std::string我必须LPTSTR,这就是我了解const wchar_t*。我这样做如下:

std::wstring widestr = std::wstring(data.begin(), data.end());
const wchar_t* widecstr = widestr.c_str();

但如果我现在检查_tcslen(widecstr),结果为4。所以我想我试图做的事情不起作用。我还在另一个问题上找到了这个引用:

  

注意:std :: string适合保存'二进制'缓冲区,而std :: wstring不是!

Source)这听起来好像我无法按照我尝试的方式存储文件数据。

所以我的问题是:我是在某个地方犯了错误还是我的方法有缺陷?也许我需要使用另一种文件类型来获得MapViewOfFile的结果?也许我需要首先将文件加载到另一种类型?

1 个答案:

答案 0 :(得分:1)

我不会提供完整的答案,因为我手边没有MCVE。然而,OP要求进一步澄清,并且关于CopyMemory()我发现了一些值得注意的事情(并且仅仅针对此发表评论有点太长了。)

CopyMemory()并不特别专注于内存映射文件。它只是一个以大小为单位从源复制数据到目标的函数。

在Google搜索CopyMemory()时,我偶然发现了{#1}}与CopyMemory()&#34;并在GameDev找到了一个和简短回答一样好的内容:

  

直接退出WINBASE.H

memcpy()
     

然后,直接从WINNT.H

#define CopyMemory RtlCopyMemory

所以,我们在这里:

std::memcpy()

  

在标题<cstring>

中定义      

#define RtlCopyMemory(Destination,Source,Length) memcpy((Destination),(Source),(Length))

     

void* memcpy( void* dest, const void* src, std::size_t count );指向的对象中的count个字节复制到src指向的对象。这两个对象都被重新解释为dest的数组。

     

如果对象重叠,则行为未定义。

对于(可能)重叠的源/目标范围的特殊情况,unsigned char有一个&#34;兄弟&#34; memmove()。在这种内存映射文件的情况下,我不相信源和目标可以重叠。因此,memcpy()可能没问题(甚至可能比memcpy()更快。)

因此,memmove()不提供&#34;内存映射文件访问魔术&#34;。这已经发生在另一个函数调用中,它肯定在OP的源代码中但在问题中没有提到:

MapViewOfFile()

  

将文件映射视图映射到调用进程的地址空间。

     

返回值

     

如果函数成功,则返回值是映射视图的起始地址。

因此,成功时,CopyMemory()返回指向文件已映射到的内存的指针。读/写访问可以像之后的任何其他进程内存访问一样完成 - 通过赋值运算符,通过MapViewOfFile()(或memcpy()),或者其他任何可想象的内容。

最后,OP的附加问题的答案:

  

我如何将数据读入&#34;其他&#34;的字符串/字节数组?我从共享内存中读取的那一面?

读取可以完全相同的方式完成,除了指向地图视图的指针成为源并且本地缓冲区成为目标。但如何确定尺寸?这个问题实际上更为通用:具有可变长度的数据占用了多少字节? C / C ++中有两个典型的答案:

  • 也可以存储数据大小(例如CopyMemory()std::string等)
  • 或以某种方式标记数据的结尾(例如,C字符串中的零终结符)。

在OP的特定情况下,第一种选择可能更合理。因此,有效负载数据(图像)的大小也可能存储在内存映射文件中。在读者方面,首先评估大小(必须具有某种std::vector类型,因此具有已知的字节数),并且该大小用于复制有效负载数据。

因此,在作家方面,它可能看起来像这样:

int

在读者方面,它看起来像这样:

/* prior something like
 * unsigned char *pBuf = MapViewOfFile(...);
 * has been done.
 */
// write size:
size_t size = data.size();
CopyMemory(pBuf, (const void*)&size, sizeof size);
// write pay-load from std::string data:
CopyMemory(pBuf + sizeof size, data.data(), size);

请注意,/* prior something like * const unsigned char *pBuf = MapViewOfFile(...); * has been done. */ // read size: size_t size = 0; CopyMemory((void*)&size, pBuf, sizeof size); // In C, I had probably done: size_t size = *(size_t*)pBuf; instead... // allocate local buffer for pay-load std::string data(size, '\0'); // read pay-load CopyMemory(&data[0], pBuf + sizeof size, size); 提供的地址与&data[0]相同。在C ++ 17之前,没有data.data()的非常量版本,因此具有std::string::data()的hack具有非const版本。