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



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

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

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

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::stringdata.length()表示我读取的文件已成功存储在那里。在msdn示例中,MapViewOfFile结果的类型是LPTSTR,所以我寻找一种方法来强制转换我必须LPTSTRstd::string,据我所知,这是一个const wchar_t*。我这样做如下:

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

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

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

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

所以我的问题是:我只是在某处犯了错误还是我的方法有缺陷?也许我需要为MapViewOfFile的结果使用另一种文件类型?也许我需要将文件初始化为另一种类型?

我不会提供一个完整的答案,因为我手头没有 MCVE。但是,OP要求更多澄清,关于CopyMemory(),我发现一些值得注意的事情(仅就此写评论有点太长了(。

CopyMemory()没有什么特别专用于内存映射文件。它只是一个将数据从源复制到目标的功能,大小以字节为单位。

在谷歌搜索CopyMemory()时,我偶然发现了"CopyMemory()vs.memcpy()",并在GameDev上找到了一个简短的答案:

直接出自赢底。H

#define CopyMemory RtlCopyMemory

然后,直接离开WINNT。H

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

所以,我们在这里:

std::memcpy()

在标头<cstring>中定义

void* memcpy( void* dest, const void* src, std::size_t count );

src指向的对象中的count字节复制到dest指向的对象。这两个对象都被重新解释为unsigned char数组。

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

对于(可能(源/目标范围重叠的特殊情况,memcpy()具有"同级"memmove()。在这种情况下,内存映射文件,我认为源和目标永远不会重叠。因此,memcpy()可能很好(甚至可能比memmove()更快(。

因此,它不是提供"内存映射文件访问魔术"的CopyMemory()。这已经发生在另一个函数调用中,该函数调用肯定在 OP 的源代码中,但在问题中未提及:

MapViewOfFile()

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

返回值

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

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

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

如何将数据读入我从共享内存中读取的"另一"端的字符串/字节数组中?

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

  • 要么存储数据的大小(如std::stringstd::vector等(
  • 或以某种方式注释数据的结尾(例如 C 字符串中的零终止符(。

在OP的特定情况下,第一种选择可能更合理。因此,付费负载数据(图像(的大小也可能存储在内存映射文件中。在读取器方面,首先评估大小(必须具有特定的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, '');
// read pay-load
CopyMemory(&data[0], pBuf + sizeof size, size);

请注意,&data[0]提供与data.data()相同的地址。在C++ 17之前,没有非常量版本的std::string::data(),因此std::string::operator[]()的黑客有一个非常量版本。

相关内容

  • 没有找到相关文章

最新更新