如何使用std :: ifstream读取具有宽字符串路径的二进制文件

16

我正在以以下方式读取二进制文件:

const size_t stBuffer = 256;
char buffer[stBuffer];
std::wstring wPath(L"blah");
std::wifstream ifs(wPath.c_str(), std::wifstream::in | std::wifstream::binary)
while (ifs.good())
{
  ifs.read(buffer, sizeof(buffer));
  ...
}

但我意识到这不是真正的二进制读取。 ifstream实际上会读取一个字节并将其转换为宽字符。因此,如果二进制文件具有以下内容0x112233...ff,实际上读取的是0x110022003300...ff00

这让我感到很困惑:首先,我只需要使用宽fstream,因为文件名是非拉丁文。其次,如果我说fstream是二进制的,为什么read会读取宽字符?下面的代码实现了我想要的效果。是否有一种方法可以使用std fstream实现相同的效果?

FILE* ifs = _wfopen(L"blah", L"rb");
while (!feof(ifs))
{
  size_t numBytesRead = fread(buffer, 1, sizeof(buffer), ifs);
  ...
}
1个回答

13

当前的C++标准不提供宽字符路径。即使是wchar_t版本也接收普通的const char*文件名。您已经使用了编译器扩展,因此请继续使用此扩展与普通的ifstream:

std::wstring wPath(L"blah");
std::ifstream ifs(wPath.c_str(), std::ios::in | std::ios::binary)

编辑:考虑使用utf-8字符串替代宽字符串,并使用Boost.Nowide(尚未包含在Boost中)来打开文件。

编辑:Boost.Nowide已被纳入Boost。此外,Windows 10 添加了对UTF-8的支持,可以通过清单启用其窄字符串API。这使得所有宽字符接口几乎无法移植且多余。


1
“std::wstring::c_str()” 返回 “const wchar_t *”,而“std::ifstream”的构造函数需要“const char *”。这就是为什么 rturrado 使用了 w 版本的原因。(我讨厌 iostreams 假设字节可能是有符号字符。) - Adrian McCarthy
2
@Adrian:w版本的构造函数也接受const char *(请参见标准)。wchar_t版本是编译器扩展,它适用于Microsoft C++编译器,这可能是OP使用的编译器。我的代码在他的实现上可以正常工作,因为他已经使用了这个扩展。所以,请不要因为你没有验证或理解我说的话而投反对票,你可能是错的。 - Yakov Galka
我在Windows上使用Visual Studio,而在Linux上使用英特尔编译器。你的解决方案在Windows上运行良好。我还没有在Linux上尝试过。这是一个相当优雅的解决方案。虽然我不想依赖编译器扩展,但我更希望您能坚持标准,也许将字符集作为ifstream的模板参数来指定,您认为可以做到吗? - rturrado
UTF-8在Linux下更好,但我认为在MS-Windows下不起作用,然而...那将被视为当前语言环境而不是UTF-8。从您提供的解释UTF-8的文档链接中可以看到:“[...]此外,由于UTF-8不能设置为窄字符串WinAPI的编码方式[...]”--换句话说,你几乎需要为每个平台使用不同的调用,对吧?或者在任一平台上使用wchar_t函数。 - Alexis Wilke
@ybungalobill:是的,那篇关于UTF-8的文档真的很好。我希望MS-Windows也选择UTF-8,但他们定义了那个愚蠢的UNICODE宏,大多数人甚至不知道支持字符串的大多数函数都有两个版本(A和W...)。无论如何,我同意。一个“简单”的方法是将所有系统特定的函数放在一个文件中,或者至少放在一个目录中(取决于您的项目大小),然后调用这些函数而不是直接调用系统函数。这样,您可以将这100个调用更改为这些覆盖,并且每个OS特定函数变成1个调用,总共可能是10个。 - Alexis Wilke
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接