【问题标题】:Unicode filenames on FAT-32?FAT-32 上的 Unicode 文件名?
【发布时间】:2023-03-11 10:22:01
【问题描述】:

据我了解 - NTFS 支持 Unicode 文件名(如 Micorsoft 声称的 UTF-16?)。

但官方 MSDN 文档对于使用哪些代码页在 FAT-32 上存储文件名(文件路径)非常含糊。

这里说 OEM 代码页(我假设是 CP437)用于存储文件名:http://msdn.microsoft.com/en-us/library/windows/desktop/dd317748.aspx

但事实证明,可以有不同的 OEM 代码页,CP437 就是其中之一:http://msdn.microsoft.com/en-us/library/windows/desktop/dd317752.aspx

现在我们都知道,像 mount 这样的实用程序支持更多不同的 FAT 代码页,而不仅仅是 OEM 代码页集。

那么,FAT-32 文件名的实际 cdepage 是什么?这取决于创建 FAT 卷时的系统代码页? FAT 能否支持真正的双字节字符集代码页,如 UTF-16?或者像 UTF-8 这样的多字节字符集代码页是限制?

还有更具体的问题: 当我使用 CreateFileW 函数(正如 MSDN 所述,它使用 UTF-16 作为文件名代码页)在 FAT-32 卷上创建文件时会发生什么?

【问题讨论】:

    标签: windows winapi unicode codepages fat32


    【解决方案1】:

    您可能需要在这里进行实验。这是一个很好的问题,我不是 100% 有信心,但是:

    那么,FAT-32 文件名的实际代码页是什么?这取决于创建 FAT 卷时的系统代码页?

    “OEM 代码页”,无论是用于系统的。

    FAT 能否支持真正的双字节字符集代码页,如 UTF-16?或者像 UTF-8 这样的多字节字符集代码页是限制?

    不,我认为 FAT 不能直接支持 UTF-16 或 UTF-8。也就是说,Microsoft 以带外方法存储 Unicode 文件名。因此,一个文件有两个文件名。 (这也是您可以拥有超过 8.3 个字符的文件名的方法。)

    还有更具体的问题:当我使用 CreateFileW 函数(如 MSDN 所述,使用 UTF-16 作为文件名代码页)在 FAT-32 卷上创建文件时会发生什么?

    传递给CreateFileW 的Unicode 文件名直接存储在带外文件名中。它被重新编码到 OEM 代码页中(无论系统上发生了什么)并放在那里。如果它不能转换成 OEM 代码页,或者超过 8.3 个字符,Windows 会调用类似 FILENA~1.TXT 的文件。

    这些答案的一些引用:

    首先,this page 告诉我们 OEM 代码页!= Windows 代码页:

    创建 FAT 文件的非 Unicode 应用程序有时必须使用标准 C 运行时库转换函数在 Windows 代码页字符集和 OEM 代码页字符集之间进行转换。使用文件系统函数的 Unicode 实现,没有必要执行这样的转换。

    在典型的美国系统上,OEM 代码页是 "CP437",但 Windows 代码页是 Windows-1252(我相信,FooA 调用使用 Windows 代码页,通常是美国人的 Windows-1252机器,但取决于区域设置)。

    如果您有可用的 FAT 卷,您可以看到这一点。字符“Σ”(U+03a3)在 Windows-1252 中不存在,但在 CP437 中存在。您可以使用dir /X 查看短文件名和长文件名。使用名为 asdfΣ.txt 的文件,您将看到:

    ASDFΣ.TXT    asdfΣ.txt
    

    但是,使用名为“asdfΛ.txt”的文件(Λ 在 CP437 或 Windows-1252 中均不存在),您会看到:

    ASDF~1.TXT   asdf?.txt
    

    (您可能会看到?,因为cmd.exe 的字体无法显示Λ。)

    有关长文件名的信息,请参阅this Wikipedia article

    另外,有趣的是,如果您将文件命名为“asdf©.txt”,您可能会得到:

    ASDFC.TXT    asdfc.txt
    

    ...我在这里不是 100% 确定,但我认为 Windows 巧妙地决定用“c”代替 ©,并同样显示它。如果您将字体更改为不基于栅格的字体,例如 Consolas,您会看到:

    ASDFC.TXT    asdf©.txt
    

    这就是您应该使用FooW 函数的原因。

    【讨论】:

    • 非常感谢您的回答。我认为主要问题已解决:Unicode 文件名也存储在 FAT 上。但出于好奇,我想再澄清几点:
    • 实际的 OEM 代码页是否存储在 FAT 卷上的某个位置(当然不是页面本身,而是它的 id)?或者实际的 OEM 代码页并不重要(因为它们都是 SBCS),只需要在控制台中正确显示文件名?
    • LFN 文件名中的 unicode 代理对会发生什么情况?它们是被截断为单个 2 字节字(因为实际的 LFN 代码页是 UCS-2 而不是 UTF-16)还是按原样存储?
    • 我猜“哪个 OEM 代码页”没有存储在 FAT 中,而是只是假设。我会查看 FAT 规范本身——如果它被存储,那就是会告诉你的。我快速浏览了 FAT 的布局,但找不到任何合适的东西。此外,Linux 胖驱动程序有一个选项来指定代码页,但在其他情况下假定为 CP437。 (见man mount。)
    • LFN 文件名存储为 UTF-16,这意味着 BMP 之外的字符应存储为代理对。 LFN 上的维基百科文章说 UTF-16,所以我们希望它是准确的。 Windows 确实允许我在 FAT 上的文件名中使用非 BMP 字符,并且这些字符必须使用代理对进行编码。
    【解决方案2】:

    基本 FAT 或 FAT32 目录条目仅支持当前 OEM 代码页中的短名称(旧的 DOS 8.3 格式)。但是,在 Windows 下使用的 VFAT(支持长文件名的 FAT)可以以 UTF-16 格式为每个文件额外存储一个所谓的long filename

    【讨论】:

    • 感谢您指出 VFAT LFN 文章!它用实际的代码页澄清了一些细节(所以它是 UCS-2)。但@Thanatos 提供了关于该主题的更广泛的解释。
    • 虽然文档说 FAT32 是 UCS-2,但 Explorer 很可能实际上将它们视为 UTF-16。 (我不相信控制台窗口支持完整的 Unicode 集,因为它基于每字符 16 位的数组;它可能只支持 UCS-2。)
    猜你喜欢
    • 2016-02-10
    • 1970-01-01
    • 2014-08-27
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多