您可能无法想象,使用C++标准库在Windows应用程序中打开文件这样基本的操作竟然有些棘手...但事实就是如此。在此处所指的Unicode是UTF-8格式,但我可以进行转换为UTF-16或其他格式,重点是获取一个能够处理Unicode文件名的ofstream实例。在我自己动手之前,是否有更好的解决方案?特别是一种跨平台的方法?
C++标准库不支持Unicode。 char
和wchar_t
不一定是Unicode编码。
在Windows上,wchar_t
是UTF-16,但标准库中没有直接支持UTF-8文件名的方法(在Windows上,char
数据类型不是Unicode)
使用MSVC(因此使用Microsoft STL),提供了一个以const wchar_t*
文件名作为参数的文件流构造函数,允许您创建流如下:
wchar_t const name[] = L"filename.txt";
std::fstream file(name);
然而,C++11标准没有规定这种重载(它只保证基于char
的版本存在),因此这种重载也不存在于其他STL实现(例如MinGW(-w64)的GCC libstdc++),截至g++ 4.8.x版本。需要注意的是,就像在Windows上的char
不是UTF8一样,在其他操作系统上wchar_t
可能不是UTF16。因此,总体来说,这不太具有可移植性。按照标准定义,使用wchar_t
文件名打开流并未被定义,而在char
中指定文件名可能较为困难,因为不同操作系统使用的字符编码也不同。
wchar_t
当然只是一个16位宽字符类型,可以用来存储任何你喜欢的东西。它并不关心编码。但是接受wchar_t
参数的Win32 API希望它们包含UTF-16数据。自Windows 2000以来,Windows API就没有使用UCS-2了。 - jalfwchar_t
中实际存储的是什么(而不是接近什么),是一个 UTF-16 代码单元。它不是 UCS-2,虽然它接近 UCS-2,但更接近 UTF-16 代码单元(因为这才是它实际上的内容)。UTF-16 指定一个代码点由一个或两个代码单元表示,后者称为代理对。 - jalf自从C++17以来,有一种跨平台的方法可以使用std::filesystem ::path 重载打开Unicode文件名的std :: fstream。示例:
std::ofstream out(std::filesystem::path(u8"こんにちは"));
out << "hello";
std::filesystem::u8path(u8"whatever")
。 - fkorsa根据http://msdn.microsoft.com/en-us/library/4dx08bh4.aspx,Visual C++ 的当前版本中 std::basic_fstream 提供了一个 open()
方法,该方法接受一个 wchar_t* 参数。
看一下Boost.Nowide:
#include <boost/nowide/fstream.hpp>
#include <boost/nowide/cout.hpp>
using boost::nowide::ifstream;
using boost::nowide::cout;
// #include <fstream>
// #include <iostream>
// using std::ifstream;
// using std::cout;
#include <string>
int main() {
ifstream f("UTF-8 (e.g. ß).txt");
std::string line;
std::getline(f, line);
cout << "UTF-8 content: " << line;
}
std::ifstream
的 Qt:return std::wstring(reinterpret_cast<const wchar_t*>(qString.utf16()));
std::basic_ifstream
构造函数通常不接受 const w_char*
,但是在 MS 的 STL 实现中 却可以。对于其他实现,您可能需要调用 qString.utf8()
,并使用 const char*
构造函数。basic_ifstream
构造函数是 Microsoft 特定的 C++ 库实现扩展。其他 Windows 编译器可能会或可能不会提供这些构造函数。无论如何,正如 此答案 所解释的那样,您不需要担心字符编码或使用哪个构造函数。只需传递 filesystem::path
,它就可以在任何操作系统上运行。 - IInspectableutf8()
几乎是恶意的,因为它经常不会失败。 - IInspectablestd::wofstream
、std::wifstream
和 std::wfstream
。它们支持 Unicode 文件名。文件名必须是 wstring
,wchar_t
数组,或者带有 _T()
宏或在文本前加上 L
前缀。std::wfstream
是Unicode
的证据吗?据我所知,它们只使用wchar_t
,这是一个宽字符,通常为16位
。但内容可能是Unicode
,也可能不是。 - Adrian Mairefile << L"фыв" << endl;
,但它不仅没有写入,还停止了通过file
流进行任何进一步的写入。因此,我改用了winAPI的WriteFile
。 - Bracketswofstream
使用 wchar_t
作为其信息单位。它不提供基于 wchar_t
的任何字符串类型的构造函数。如果您的编译器提供了这个功能,那么它是一个非标准扩展。如果该编译器是 Microsoft 编译器,您可以同样使用 ofstream
。非标准扩展可用于任何 basic_ofstream
类模板实例化。 - IInspectable
std::wofstream
这样的数据类型呢?注意w! - sergiol