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

9

我正在开发一个库(pugixml),其中提供了使用窄字符C字符串加载/保存XML文档的文件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并使用类似_wfopen的感知函数来打开文件来实现)。
我可以看到不同的利弊,我不确定哪种权衡最好。
一方面,在所有平台上使用一致的编码肯定是好的。这意味着您可以使用从XML文档中提取的文件路径来打开其他XML文档。此外,如果使用库的应用程序采用UTF-8,则在库中打开XML文件时无需进行额外的转换。
另一方面,这意味着文件加载的行为不再与标准函数相同 - 因此,通过库访问文件不等同于通过标准fopen/std :: fstream访问文件。似乎虽然一些库采用UTF-8路径,但这基本上是一个不受欢迎的选择(这是真的吗?),因此,针对使用许多第三方库的应用程序,它可能会增加混淆而不是帮助开发人员。
例如,将argv[1]传递到load_file中当前适用于在Windows上使用系统区域设置编码的路径(例如,如果您使用俄语区域设置,则可以以此方式加载任何具有俄语名称的文件,但是您将无法加载具有日语字符的文件)。切换到UTF-8将意味着仅ASCII路径有效,除非您通过某种其他特定于Windows的方式检索命令行参数。
当然,这将对库的某些用户造成破坏性变化。
我有没有漏掉任何重要的观点?是否还有其他采用同样方法的库?对于C ++来说,是保持不一致的文件访问更好,还是追求统一的跨平台行为?
请注意,问题是关于打开文件的默认方式 - 当然,没有什么阻止我添加带_utf8后缀的另一对函数或以其他方式指示路径编码。

2
三件事:(1)为什么不在内部转换为UTF-16,然后在Windows上使用_wfopen/std::ifstream(wchar_t *)?生成的文件对象与非wchar函数打开的对象相同。(2)您是否阅读过http://utf8everywhere.org,并且您是否同意其中的观点?(3)请参见https://dev59.com/02gu5IYBdhLWcg3wv5ca。 - nneonneo
  1. 这正是第二种方法的工作原理
  2. 我已经阅读过了。我同意在跨平台应用程序中,UTF-8通常更优秀,但库可能会有所不同 - 全世界都这么认为吗? :)
- zeuxcg
另一个在Windows上使用UTF-8(而不是宽字符)的库:gtkmm。尽管它也存在其他问题。 - Yakov Galka
值得注意的是,微软正在努力推动FileSystem TS,正是出于这些原因。他们甚至实现了对Boost.FileSystem v2的支持,只是为了在VS2013中有一个东西。现在FSTS已经完成,在所有主要编译器/标准库供应商中,他们拥有第一个实现。他们希望像其他人一样看到这个问题得到解决。 - Nicol Bolas
1个回答

8

越来越多的人认为在跨平台代码中应该只使用UTF-8,并在Windows中自动执行必要的转换。utf8everywhere 很好地介绍了优先选择UTF-8编码的原因。

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

就个人而言,我避免使用 wchar_t/wstring 函数最强烈的原因就是为了避免我的API重复。保持API函数数量的减少,以减少外部维护、文档和代码路径重复成本是很有价值的。细节可以在内部解决。由Windows ANSI / Unicode分裂引起的重复API混乱可能已经足够说明这一点,从而避免在自己的API中出现这种情况。


1
其次,这确实是最好的可能方法,使事情变得更简单。 - Artyom
2
是的,更具体地说,在Windows上,将文件名转换为宽字符并使用宽API。有很多库只是将“const char *”传递给“fopen(...)”,这将使打开具有任意文件名(即具有当前代码页之外的字符)的文件变得几乎不可能。 - roeland

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