Windows代码页与标准C / C ++文件名的交互?

客户抱怨我们的代码用于在文件名中写入带有日文字符的文件,但在所有情况下都不再有效。 我们总是使用好的旧char *字符串来表示文件名,所以它对我来说有点令人震惊,它曾经有效,我们没有做任何我知道应该让它停止工作的事情。 我让他们发给我一个带有嵌入式文件名的文件,从我们的软件导出它,看起来字符串使用hex字符82和83作为双字节序列的第一个字符来表示日文字符。 在线浏览让我相信这可能是SHIFT_JIS和/或Windows代码页932。

在我看来,之前发生的事情是使用此代码页的fopen和ofstream :: open接受的文件名; 现在只有fopen呢。 我已经检查了Visual Studio fopen docs,我没有看到什么使得可接受的字符串传递给fopen。

在短期内,我希望有人可以为我提供一些关于特定Windows fopen与ofstream :: open问题的信息。 从长远来看,我真的想知道在Windows,Linux和OS X上用C ++打开Unicode(和其他?)文件名的可接受方式。

编辑添加:我认为开放工作是在“C”语言环境中完成的,而那些不工作的开放是在客户的默认语言环境中完成的。 然而,多年以来一直如此,该程序的旧版本今天仍在他们的系统上运行,所以这似乎是解释我们所看到的问题的一个远景。

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

我仍然感兴趣,如果有人对这种行为有解释(为什么它会神秘地改变 – 也许是VS2005的服务包?)并且希望在便携式C ++代码中整理一个全面的“最佳实践”来处理Unicode文件名。

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

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

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

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

从长远来看,您可能会考虑转向Unicode(并使用_wfopen,wofstream)。

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

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

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

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

您可能必须将线程区域设置设置为系统默认区域设置。 请在此处查看可能的问题原因: http : //connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?反馈ID = 100887

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

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

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

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

VS2005的所有变通方法都有其缺点:

  1. 将代码转换为在任何地方使用Unicode

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

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

匹配setlocale:

 setlocale (LC_ALL, ("." + lexical_cast (GetACP())).c_str())