在 Rust 中,操作系统文件路径使用特定的
Path
类型而不是 str
来存储。这是因为 str
表示 UTF-8 字节序列,而内核要么不强制执行任何类型的编码 (Unix),只要斜杠用其 ASCII 代码点表示,要么以 16 位编码进行编码( Windows)。
在Java中,路径使用标准库中的String类型来表示,该类型内部使用UCS-2。这不是特定于实现的,因为某些 String 方法会以某种方式“泄漏”此编码。
Java 如何将 Unix 的任意字节序列路径表示为 Unicode?我假设它将路径视为 ASCII 或 UTF-8,以便将“原始”字节映射到 Unicode 代码点,因为路径实际上几乎总是 ASCII 或 UTF-8,但是如果存在无效的字节序列怎么办ASCII 还是 UTF-8?到 Unicode/UCS-2 的转换是否无损?是否有可来回记录的算法?如果我不想排除非拉丁字母用户,在处理 Java 中的文件路径时我应该考虑什么?
touch $(echo -e "\xc3\x28")
。这将创建一个完全有效的文件,其名称无法用 Unicode 表示。jshell
new File(".").listFiles()[0].isFile()
false
\x28
,这意味着 \xC3
已被有损地转换为 Unicode,不再代表实际路径你的问题不清楚,但这里是。
我认为“非 unicode”实际上是指“不在 Java 的内部字符编码中”。
几乎不存在非 Unicode 字符。 Unicode 15.1 代表 149,813 个字符,几乎是人类使用的所有字符,包括学者和权威机构确定的过去和现在、“活着”和“死了”的语言和文字。加上一堆表情符号🤷🏽u200d♂️。随着越来越多的晦涩字符被识别出来,Unicode 也在不断增长。
Java 作为平台设计的一个主要方面是让您与主机操作系统的细节隔离。
其中包括有关主机操作系统所使用的文件系统的详细信息。如果您使用捆绑的 Java 类与文件交互(提示:NIO.2),那么您无需关心主机操作系统文件系统内部的位和字节。处理这些文件系统详细信息是 (a) 编写操作系统的人员和 (b) 编写 Java 实现(例如 OpenJDK)的人员的工作。 Java 的部分乐趣并不在于处理这些事情。
例如,我在 macOS Sonoma 14.4.1 的 Finder.app 中创建了嵌套的文件夹层次结构。我使用谷歌翻译翻译了俄语中的“苹果”,罗马尼亚语中的“香蕉”,日语中的“胡萝卜”。在该文件夹中,我创建了一个 UTF-8 编码的纯文本文件,名称为法语“data”。该文件包含一行:
Bonjour!
。
使用 Java NIO.2,我通过
Path
(复数)类用 Paths
对象表示该文件的路径。
final String HOME = System.getProperty( "user.home" ); // /Users/basil_dot_work for me on macOS.
final Path path = Paths.get( HOME, "Яблоко" , "Banană" , "にんじん" , "données.txt" ); // Apple in Russian, Banana in Romanian, Carrot in Japanese.
这里的重点是,我不知道苹果工程师如何在各个文件夹名称中对各种语言进行编码。我不在乎。 Java 代表我负责与 macOS 文件系统交互。 它的工作原理要感谢 Apple 开发人员和任何其他为 OpenJDK 项目 macOS 分支做出贡献的人。
我需要做的就是在我的 Java 代码的.java
源文件中以 UTF-8 编码表示 Unicode 字符。我的IDE (IntelliJ) 使用的编译器知道如何解析 UTF-8,然后编码为 Java 字节码。在运行时,JVM 会破译该字节码中的预期文本,以某种内部定义的编码来表示文本。 (顺便说一句,Java 的内部定义的编码不一定是 UCS-2。我依稀记得,现代 JVM 实现可能会使用更有效的东西来处理面向拉丁语的内容。同样,我不在乎 - 这就是 Java 的好处。) 接下来,我使用 打开该文件来读取
Stream
行,每行都是 String
对象。
try
{
Files
.lines( path , StandardCharsets.UTF_8 )
.forEach( System.out :: println );
} catch ( IOException e )
{
throw new RuntimeException( e );
}
在 Java 22 中运行时的结果:
你好!现在我们可以将完全相同的编译类带到 Linux 机器上,并确信它将成功运行。 Linux 特有的 JVM 将知道如何在字节码编码的文件夹/文件名和 Linux 文件系统自身对这些相同 Unicode 字符的编码之间进行协调。