2009-01-26 13 views
5

一位客户抱怨说,我们的代码用于在文件名中使用日文字符编写文件,但不再适用于所有情况。我们总是使用好的旧char *字符串来表示文件名,所以它对我来说有点令人震惊,它曾经起作用,而且我没有做任何我知道应该使它停止工作的事情。我让他们向我发送一个带有嵌入文件名的文件,并将它从我们的软件中导出,它看起来像字符串使用十六进制字符82和83作为双字节序列的第一个字符来表示日文字符。在网上搜索引导我相信这可能是SHIFT_JIS和/或Windows代码页932.Windows Codepage与标准C/C++文件名的交互作用?

它看起来像我以前发生的事情是既fopen和ofstream ::打开接受的文件名使用此代码页;现在只有fopen。我已经检查过Visual Studio fopen文档,并且我没有看到什么让一个可接受的字符串传递给fopen。

在短期内,我希望有人可以对特定的Windows fopen和ofstream :: open问题提供一些启示。从长远来看,我真的很想知道开放统一的接受的方式在C++中的文件名,在Windows,Linux和OS X.

编辑补充(及其他):我认为,将打开工作是在“C”语言环境中完成的,而不工作的是在客户的默认语言环境中完成的。然而,这种情况多年来一直如此,而且该计划的旧版本今天仍然适用于他们的系统,所以这对于解释我们所看到的问题来说似乎是一个长远的目标。

更新:我发送了一个小测试程序给客户。它已经证实fopen可以正确使用SHIFT_JIS文件名,并且std :: ofstream不会。这是在Visual Studio 2005中发生的,无论我使用的是默认语言环境还是“C”语言环境。

如果有人对此行为有解释(为什么它会神秘地改变 - 也许是VS2005的服务包?),并希望将便携式Unicode文件名的全面“最佳实践”放在一起C++代码。

+0

也许你可以给的时间框架时发生这种情况。 Windows在过去几年中发生了很大变化。 – 2009-01-26 18:45:03

+0

好点。这一变化发生在去年。 – Sol 2009-01-26 19:32:10

回答

0

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

+2

不,所有本地Linux文件系统都忽略字符编码(但是,一些非本地FS很在意)。文件名是字节字符串,唯一的特殊字符是斜线和空字符。任何编码必须由shell处理。 – 2009-01-26 19:52:17

2

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

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

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

0

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

3

像fopen或ofs​​tream :: open这样的函数将文件名称作为char *,但将其解释为在系统代码页中。

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

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

这是你如何修改系统代码页:http://www.mihai-nita.net/article.php?artID=20050611a

在你可以考虑移动到Unicode(和使用_wfopen,wofstream)的长远之计。

0

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

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

这可能会导致很大的混淆,微软已经在后来的VS版本中删除了这个怪癖。

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

  1. 将代码转换为使用Unicode无处不

  2. 使用窄字符的文件名不要打开fstreams,始终使用系统默认编码转换为他们的Unicode自己,使用宽字符文件名打开/ ctor

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

匹配的setlocale:

setlocale (LC_ALL, ("." + lexical_cast<string> (GetACP())).c_str())