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

标签 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::stringLPTSTR,据我所知这是一个 const wchar_t*。我这样做如下:

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

但是如果我现在检查 _tcslen(widecstr),结果是 4。所以我想我尝试做的是行不通的。我还在另一个 SO 问题上找到了这句话:

Notice: A std::string is suitable for holding a 'binary' buffer, where a std::wstring is not!

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

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

最佳答案

我不会提供完整的答案,因为我没有 MCVE在眼前。但是,OP 要求更多说明,并且关于 CopyMemory() 我发现了一些值得注意的地方(而且只写评论有点太长了)。

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

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

Straight out of WINBASE.H

#define CopyMemory RtlCopyMemory

Then, straight out of WINNT.H

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

所以,我们在这里:

std::memcpy()

Defined in header <cstring>

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

Copies count bytes from the object pointed to by src to the object pointed to by dest. Both objects are reinterpreted as arrays of unsigned char.

If the objects overlap, the behavior is undefined.

对于(可能)重叠的源/目标范围的特殊情况,memcpy()有一个“ sibling ” memmove() .在这种内存映射文件的情况下,我认为源和目标永远不会重叠。所以,memcpy()可能没问题(甚至可能比 memmove() 更快。)

所以,它不是 CopyMemory()它提供了“内存映射文件访问魔法”。这已经发生在另一个函数调用中,它肯定在 OP 的源代码中,但在问题中没有提到:

MapViewOfFile()

Maps a view of a file mapping into the address space of a calling process.

Return Value

If the function succeeds, the return value is the starting address of the mapped view.

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

最后是OP附加题的答案:

how I could read the data into a string/byte-array on the "other" side where I read from the shared memory?

读取可以以完全相同的方式完成,除了指向 map View 的指针成为源而本地缓冲区成为目标。但是如何确定尺寸呢?这个问题其实更笼统:可变长度的数据占用了多少字节? 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, '\0');
// read pay-load
CopyMemory(&data[0], pBuf + sizeof size, size);

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

关于C++ 从磁盘读取文件并将其写入共享内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50198528/

相关文章:

支持 .h .cpp 同步的 C++ 源代码文本编辑器

c++ - 将字符指针十六进制转换为字符串并保存在文本文件中 C++

c++ - 如何在 Qt5 中启用已弃用的功能

c++ - 尝试创建表会出现 sql 逻辑错误

winapi - 如何获取 'special' Windows 文件夹(回收站等)的本地化名称?

c# - Form.TopMost 有时有效

c - 如何防止控制台应用程序在 C 中按 "Ctrl+C"时终止?

perl - 如何在 perl 中的 fork 之间共享简单标量(计数器变量)?

c - 将字符串数组附加到共享内存 - 段错误

c++ - 是否可以将包含指针的 vector 放入共享托管内存中?