6

一位客户抱怨我们的代码用于编写文件名中包含日文字符的文件,但不再适用于所有情况。我们一直只是使用良好的旧 char * 字符串来表示文件名,所以它曾经工作过让我有点震惊,而且我们没有做任何我知道应该让它停止工作的事情。我让他们向我发送了一个从我们的软件导出的带有嵌入文件名的文件,看起来这些字符串使用十六进制字符 82 和 83 作为双字节序列的第一个字符来表示日文字符。在网上闲逛让我相信这可能是 SHIFT_JIS 和/或 Windows 代码页 932。

在我看来,以前发生的事情是 fopen 和 ofstream::open 使用此代码页接受的文件名;现在只有 fopen 可以。我已经检查了 Visual Studio fopen 文档,但我没有看到任何提示可以将可接受的字符串传递给 fopen。

在短期内,我希望有人能为我阐明特定的 Windows fopen 与 ofstream::open 问题。从长远来看,我真的很想知道在 C++、Windows、Linux 和 OS X 上打开 Unicode(和其他?)文件名的公认方式。

编辑添加:我相信工作的打开是在“C”语言环境中完成的,而那些不工作的打开是在客户的默认语言环境中完成的。但是,这种情况已经存在多年了,旧版本的程序今天仍然可以在他们的系统上运行,所以这似乎无法解释我们所看到的问题。

更新:我向客户发送了一个小型测试程序。它已经验证 fopen 可以与 SHIFT_JIS 文件名一起正常工作,而 std::ofstream 不能。这是在 Visual Studio 2005 中,无论我使用的是默认语言环境还是“C”语言环境,都会发生这种情况。

如果有人对这种行为有解释(以及为什么它神秘地改变了——也许是 VS2005 的服务包?),我仍然很感兴趣,并希望将一个全面的“最佳实践”放在一起处理可移植 C++ 代码中的 Unicode 文件名。

4

6 回答 6

3

fopen 或 ofstream::open 之类的函数将文件名作为 char *,但这被解释为在系统代码页中。

这意味着它可以是表示为 Shift-JIS (cp932) 的日文字符,也可以是简体中文 (Big 5/cp936)、韩文、阿拉伯文、俄文,你可以命名它(只要它与 OS 系统代码页匹配)。

这也意味着它只能在日文系统上使用日文文件名。更改系统代码页和应用程序“停止工作”我怀疑这就是这里发生的事情(自 Win 2000 以来,Windows 在这方面没有大的变化)。

这是您更改系统代码页的方式:http: //www.mihai-nita.net/article.php?artID=20050611a

从长远来看,您可能会考虑迁移到 Unicode(并使用 _wfopen、wofstream)。

于 2009-02-09T09:36:34.087 回答
2

我不知道使用默认系统库使用 unicode 文件的任何可移植方式。但是有一些框架提供了可移植的功能,例如:

  • 对于 C:glib使用 UTF-8 格式的文件名;
  • 对于 C++:glibmm也使用 UTF-8 格式的文件名,需要 glib;
  • 对于 C++:boost可以使用 wstring 作为文件名。

我很确定 .NET/mono 框架也确实包含可移植文件系统功能,但我不知道它们。

于 2009-02-03T08:42:56.983 回答
1

有人还在看这个吗?我刚刚研究了这个问题,但在任何地方都没有找到答案,所以我可以在这里尝试解释我的发现。

在 VS2005 中,fstream 文件名处理是一个奇怪的人:它不使用系统默认编码,您可以使用 GetACP 获得并在控制面板/区域和语言/管理中设置。但总是 CP 1252——我相信。

这可能会造成很大的混乱,微软已经在以后的 VS 版本中删除了这个怪癖。

VS2005 的所有解决方法都有其缺点:

  1. 转换您的代码以在任何地方使用 Unicode

  2. 永远不要使用窄字符文件名打开 fstream,始终使用系统默认编码将它们转换为 Unicode,使用宽字符文件名 open/ctor

  3. 使用 GetACP() 检索代码页,然后执行

匹配的setlocale:

setlocale (LC_ALL, ("." + lexical_cast<string> (GetACP())).c_str())
于 2013-08-09T19:41:52.107 回答
0

Mac OS X 使用 Unicode 作为其本机字符编码。基本的字符串对象是 CFString 和 NSString。它们将字符数组存储为 Unicode。

于 2009-02-05T10:30:16.747 回答
0

我几乎可以肯定,在 Linux 上,文件名字符串是一个 UTF-8 字符串(例如,在 EXT3 文件系统上,唯一不允许的字符是斜杠和 NULL),存储在普通的char *. 手册页似乎没有提到字符编码,这让我相信它是 UTF-8 的系统标准。OS X 可能使用相同的,因为它来自相似的根源,但我对此不太确定。

于 2009-01-26T18:41:53.600 回答
0

您可能必须将线程语言环境设置为系统默认语言环境。请参阅此处了解问题的可能原因: http ://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100887

于 2009-01-26T19:37:52.740 回答