Windows API ANSI函数和UTF-8

26

能否使用Windows API的ANSI函数处理UTF-8字符串呢?

比如说,如果我有一个用UTF-8编码的路径,我可以调用CreateDirectoryA或者CreateFileA函数并传入UTF-8路径吗?还是在调用这些函数之前需要进行一些转换呢?


2
哎呀,为什么有人想要那个?我认为我们已经远远超越了Windows ME(这是最后一个需要ANSI API的Windows版本)。它们应该早就消失了,特别是对于新开发的应用程序。 - Joey
2
你从哪里获得UTF-8字符串?将您的应用程序完全转换为使用所谓的宽字符版本Windows API函数处理UTF-16字符串会更容易,正如Joey所说,始终调用具有“W”后缀的宽字符版本,而不是ANSI版本,因为后者已经过时了几十年。 - Cody Gray
13
@Joey:因为大量的C(++)库(包括标准库!)更喜欢使用基于char的字符串而不是基于wchar_t的字符串。如果Windows完全支持UTF-8,那么您就可以在整个程序中直接使用UTF-8,而无需一直在UTF-8和UTF-16之间进行转换。 - dan04
1
@dan04:UTF-16是最适合进行处理的Unicode编码(UTF-8适用于存储),可以参考这篇有趣的文章:http://unicode.org/notes/tn12/(还请注意,C#和Java都使用UTF-16编码作为其字符串类的标准编码方式)。 - user1149224
8
@user1149224说,UTF-16编码处理代码的复杂程度不亚于UTF-8处理代码。而UTF-32处理代码则简单得多。 - user253751
3个回答

19

经过证实,已被接受的答案不再准确(截至Windows版本1903(2019年5月更新))。

现在应用程序可以将进程的活动代码页设置为UTF-8。这允许...A函数(和CP_ACP)与UTF-8一起使用。执行此操作的清单如下所示

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity type="win32" name="..." version="6.0.0.0"/>
  <application>
    <windowsSettings>
      <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
    </windowsSettings>
  </application>
</assembly>

来源和额外信息:使用 Windows UTF-8 代码页


17

不要使用其他方法,直接使用MultiByteToWideChar将UTF-8转换为UTF-16编码,然后再调用宽字节API,如CreateDirectoryWCreateFileW


13
我建议您跟随Windows使用UTF-16编码,这样可以避免出现格式转换问题。只有在需要读写外部源时,才将其转换为UTF-8编码。 - casablanca
9
另一种被提倡的方法是在大部分情况下使用UTF-8,并且仅当与Windows接口通信时才转换为UTF-16。 - Keith Thompson
@casablanca,这将会给C++标准库带来一些严重的头疼问题,不幸的是,像异常消息这样的东西被硬编码为char,而不是wchar_t。有些人建议不要在异常消息中放置Unicode,但这并不是很实际,因为如果您需要传达像“无法打开文件바위처럼 단단한.txt”或“名称为바위처럼 단단한的记录不存在”的信息时,您将无法轻松地完成它。说“异常不需要Unicode”实际上意味着“您的整个代码库仅在显示目的上使用Unicode”。 - jrh
3
此回答已过时,请参考下面的更新答案。 - Erik

3
一个比使用原始Win32 API MultiByteToWideChar更简单的方法是使用ATL转换助手,例如CA2CW。您可以指定CP_UTF8作为代码页(构造函数中的第二个参数),以从Unicode UTF-8转换为Unicode UTF-16:
CreateDirectoryW( 
  CA2W( utf8Name, CP_UTF8 ) // convert from UTF-8 to UTF-16
  ... // other stuff
);

请注意,在Unicode版本(这些应该是默认版本)中,CreateDirectory只是扩展为CreateDirectoryW,因此我会删除结尾的“W”,并使用(在我看来更易读的)CreateDirectory。
CreateDirectory( 
  CA2W( utf8Name, CP_UTF8 ) // convert from UTF-8 to UTF-16
  ... // other stuff
);

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