C++ 库中的文件打开接口应该在 Windows 上使用 UTF-8 吗?

Should the file opening interface in a C++ library use UTF-8 on Windows?

我正在开发一个库 (pugixml),除其他外,它为使用窄字符 C 字符串的 XML 文档提供文件 load/save API:

bool load_file(const char* path);
bool save_file(const char* path);

目前路径被逐字传递给 fopen,这意味着在 Linux/OSX 上您可以传递 UTF-8 字符串来打开文件(或任何其他字节序列是有效路径), 但在 Windows 上你必须使用 Windows ANSI 编码 - UTF-8 将不起作用。

文档数据(默认情况下)使用 UTF-8 表示,因此如果您有一个带有文件路径的 XML 文档,您将无法将从文档检索到的路径传递给 load_file 按原样运行 - 或者更确切地说,这不适用于 Windows。该库提供了使用 wchar_t:

的替代函数
bool load_file(const wchar_t* path);

但是使用它们需要付出额外的努力才能将 UTF8 编码为 wchar_t。

一种不同的方法(SQlite 和 GDAL 使用的 - 不确定是否有其他 C/C++ 库这样做)涉及将路径视为 Windows 上的 UTF-8(这将通过将其转换为 UTF-16 并使用 wchar_t 感知函数(如 _wfopen 打开文件)来实现。

我看到了不同的优缺点,我不确定哪种权衡是最好的。

一方面,在所有平台上使用一致的编码肯定是好的。这意味着您可以使用从 XML 文档中提取的文件路径来打开其他 XML 文档。此外,如果使用该库的应用程序采用 UTF-8,则在通过该库打开 XML 文件时无需进行额外的转换。

另一方面,这意味着文件加载行为不再与标准函数相同 - 因此通过库访问文件不等同于通过标准函数访问文件 fopen/std::fstream。看起来虽然有些库采用 UTF-8 路径,但这在很大程度上是一个不受欢迎的选择(这是真的吗?),因此给定一个使用许多第三方库的应用程序,它可能会增加混乱而不是帮助开发人员。

例如,将 argv[1] 传递到 load_file 目前适用于在 Windows 上使用系统区域设置编码的路径(例如,如果您有俄语区域设置,则可以加载任何带有俄语的文件像这样的名称,但您将无法加载带有日语字符的文件)。切换到 UTF-8 意味着只有 ASCII 路径有效,除非您以其他一些 Windows 特定的方式检索命令行参数。

当然,对于图书馆的某些用户来说,这将是一个重大变化。

我是否遗漏了任何要点?是否有其他图书馆采用相同的方法?什么对 C++ 更好 - 在文件访问中始终不一致,还是争取统一的跨平台行为?

请注意,问题是关于打开文件的默认方式 - 当然没有什么能阻止我添加 另一个 对带有 _utf8 后缀的函数或在某些文件中指示路径编码其他方式。

越来越多的人认为,您应该只在跨平台代码中使用 UTF-8,并在适当的地方在 Windows 中自动执行转换。 utf8everywhere 很好地概述了首选 UTF-8 编码的原因。

作为最近的一个例子,libtorrent 弃用了所有处理 wchar_t 文件名的例程,而是要求库用户在传入文件名之前使用他们的 wchar_t-to-utf8 转换函数。

就个人而言,我必须避免使用 wchar_t/wstring 函数的最重要原因就是避免重复我的 API。减少 API 中的函数数量,以减少外部维护、文档和代码路径重复成本是很有价值的。细节可以在内部制定。由 Windows ANSI/Unicode 拆分造成的重复 API 的混乱可能足以在您自己的 API 中避免这种情况。