客户抱怨我们的代码用于在文件名中写入带有日文字符的文件,但在所有情况下都不再有效。我们总是使用好的旧char *字符串来表示文件名,所以它对我来说有点震撼它曾经有效,我们没有做任何我知道应该让它停止工作的事情。我让他们发给我一个带有嵌入式文件名的文件,从我们的软件导出它,看起来字符串使用十六进制字符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”语言环境中完成的,而那些不起作用的打开是在客户的默认语言环境中完成的。然而,多年以来一直如此,该程序的旧版本今天仍在他们的系统上运行,所以这似乎是解释我们所看到的问题的一个远景。
更新:我向客户发送了一个小测试程序。它已经验证fopen与SHIFT_JIS文件名一起工作正常,而std :: ofstream则没有。这是在Visual Studio 2005中,无论我使用的是默认语言环境还是“C”语言环境,都会发生这种情况。
我仍然感兴趣,如果有人对这种行为有解释(为什么它会神秘地改变 - 也许是VS2005的服务包?)并且希望在便携式C ++中整理一个全面的“最佳实践”来处理Unicode文件名代码。
答案 0 :(得分: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)。
答案 1 :(得分:2)
我不知道使用默认系统库的任何可移植方式使用unicode文件。但是有一些框架提供了可移植的功能,例如:
我很确定.NET / mono框架也包含可移植文件系统功能,但我不知道。
答案 2 :(得分:0)
我几乎可以肯定,在Linux上,文件名字符串是UTF-8字符串(例如,在EXT3文件系统上,唯一不允许的字符是斜线和NULL),存储在普通char *
中。手册页似乎没有提到字符编码,这使我相信它是UTF-8的系统标准。 OS X可能使用相同的,因为它来自相似的根,但我对此不太确定。
答案 3 :(得分:0)
您可能必须将线程区域设置设置为系统默认区域设置。 请看这里找出问题的可能原因: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100887
答案 4 :(得分:0)
Mac OS X使用Unicode作为其本机字符编码。基本的字符串对象是CFString和NSString。它们将字符数组存储为Unicode。
答案 5 :(得分:0)
有人还在看这个吗?我刚刚研究过这个问题,在任何地方都找不到答案,所以我可以尝试在这里解释我的发现。
在VS2005中,fstream文件名处理是奇怪的:它不使用系统默认编码,你使用GetACP获得并在控制面板/区域和语言/管理中设置。但总是CP 1252 - 我相信。
这可能会造成很大的混乱,微软已经在以后的VS版本中删除了这个怪癖。
VS2005的所有变通方法都有其缺点:
将代码转换为在任何地方使用Unicode
永远不要使用窄字符文件名打开fstreams,总是使用系统默认编码将它们转换为Unicode,使用宽字符文件名open / ctor
使用GetACP()检索代码页,然后执行
匹配setlocale:
setlocale (LC_ALL, ("." + lexical_cast<string> (GetACP())).c_str())