NTFS中存储的文件名是什么编码?

vro*_*oom 41 windows unicode ntfs

我刚刚开始编写一些程序来处理WinXP系统上具有非英文名称的文件名.我已经完成了一些关于unicode的推荐阅读,我认为我得到了基本的想法,但有些部分对我来说仍然不是很清楚.

具体来说,什么编码(UTF-8,UTF-16LE/BE)是存储在NTFS 中的文件(不是内容,而是文件的实际名称)?是否可以使用fopen()打开任何文件,它接受一个char*,或者我别无选择,只能使用wfopen(),它使用wchar_t*,并且可能需要一个UTF-16字符串?

我尝试手动输入UTF-8编码的字符串给fopen(),例如.

unsigned char filename[] = {0xEA, 0xB0, 0x80, 0x2E, 0x74, 0x78, 0x74, 0x0}; // ?.txt

FILE* f = fopen((char*)filename, "wb+");
Run Code Online (Sandbox Code Playgroud)

但这就是'ê°€.txt'.

我觉得UTF8编码的字符串足以打开Windows下的任何文件名,因为我似乎依稀记得一些Windows应用程序传递(char*),而不是(wchar_t*),并且没问题.

任何人都可以对此有所了解吗?

vil*_*pam 37

NTFS以UTF16存储文件名,但fopen使用ANSI(不是utf8).

要使用UTF16编码的文件名,您需要使用文件打开调用的Unicode版本.通过在项目中定义UNICODE和_UNICODE来完成此操作.然后使用CreateFile调用或wfopen调用.

  • 如果更改要使用UNICODE定义构建的项目太大而无法更改,则可以在非unicode构建中调用`wfopen()`或`CreateFileW()`. (14认同)
  • NTFS允许任何16位值序列用于名称编码,除了0x0000.这意味着支持UTF-16代码点,但文件系统不检查序列是否有效UTF-16.\ [[源(https://en.wikipedia.org/wiki/NTFS#Internals)\] (3认同)
  • 鉴于 Windows NT 和 NTFS 比 UTF-16 标准更旧,是否有可能改用旧的 UCS-2? (2认同)
  • @hillu Win32 Unicode 函数使用“wchar_t”字符串。NT 和 NTFS 可能早于 UTF-16,但“wchar_t”可用于 Windows 上的 UCS-2 和 UTF-16,并且 Microsoft 从 UCS-2 迁移到 Win2K 中使用 UTF-16。 (2认同)

Chr*_*cke 14

fopen() - 在Windows上的MSVC中(默认情况下)不采用utf-8编码的char*.

不幸的是,utf-8最近才发明在伟大的计划中.Windows API分为Unicode和Ansi版本.采用或处理字符串的每个窗口api实际上都有W或A后缀 - W表示"宽"字符/ Unicode,A表示Ansi.Macro magic将所有这些隐藏在开发人员之外,因此您只需使用char*或wchar_t*调用CreateFile,具体取决于您的构建配置,而不知道区别.

'Ansi'编码实际上不是特定的编码: - 但意味着用于"char"字符串的编码特定于PC的语言环境设置.

现在,因为c-runtime函数 - 比如fopen - 需要在没有开发人员知识的情况下默认工作 - 在Windows系统上,他们希望在windows本地编码中接收它们的字符串.msdn表示微软的c-runtime api setlocal可以改变当前线程的语言环境 - 但是具体说它对于每个字符需要超过2个字节的任何语言环境都会失败 - 比如utf-8.

因此,在Windows上没有捷径.您需要使用wfopen或本机API CreateFileW(或使用Unicode构建设置创建项目,只需调用Createfile)和wchar_t*字符串.

  • 实际上,有一个快捷方式:您可以将UTF-8字符串转换为Unicode,使用[GetShortPathNameW]创建一个仅ASCII的"短路径名"(http://msdn.microsoft.com/en-us/library/windows/ desktop/aa364989(v = vs.85).aspx),并将其传递给`fopen`.这是将非ASCII文件名传递给只使用`fopen`打开文件的旧库(或用便携式C编写的文件库)的唯一方法. (2认同)

use*_*342 5

正如其他人所回答的,处理UTF-8编码字符串的最佳方法是将它们转换为UTF-16并使用本机Unicode API,如_wfopenCreateFileW.

但是,这种方法在调用fopen()无条件使用的库时无济于事,因为它们不支持Unicode,或者因为它们是用便携式C编写的.在这种情况下,仍然可以利用传统的"短路径"来转换将UTF-8编码的字符串转换成可用的ASCII格式fopen,但需要一些脚法:

  1. 使用将UTF-8表示转换为UTF-16 MultiByteToWideChar.

  2. 使用GetShortPathNameW获得"短路径",这是ASCII只.GetShortPathNameW将它作为带有全ASCII内容的宽字符串返回,您需要通过每个无损复制转换将其简单地转换为窄字符串wchar_t char.

  3. 将短路径传递fopen()给最终将使用的代码fopen().请注意,该代码打印的错误消息(如果有)将引用难看的"短路径"(例如KINTO~1代替kinto-un-???).

虽然这不是一个推荐的长期策略,但由于Windows短路径是可以按卷关闭的传统功能,因此它可能是将文件名传递给使用的代码fopen()和其他与文件相关的API调用的唯一方法(stat,accessANSI版本CreateFile和类似版本).