Java Paths.get() Linux 上的奇怪行为
Java Paths.get() strange behavior on Linux
我目前正在编写一些代码,其中我经常使用文件。我使用 Java 7 nio classes 路径和路径实现了所有文件路径处理(连接、规范化等)。在 Windows 上,一切都按预期工作,但是在 Linux 上,路径 class 行为似乎被破坏了。
例如下面的代码:
System.out.println(File.separator);
System.out.println(FileSystems.getDefault());
Path path = Paths.get("../dir1/", "\dir2\file1").toAbsolutePath().normalize();
System.out.println(path);
if(path.toFile().exists()) {
System.out.println(path + " exists");
}
on Windows 打印以下输出:
\
sun.nio.fs.WindowsFileSystem
D:\projects\dir1\dir2\file1
true
但 Linux Ubuntu 14.04 上的代码相同 Java 1.7.0_79(64 位)和 Java 1.8.0_60(64 位)使路径未规范化:
/
sun.nio.fs.LinuxFileSystem
/home/semi/dir1/\dir2\file1
此外,即使文件位于路径 /home/semi/dir1/dir2/file1
中,它也被 path.toFile().exists()
报告为不存在。
我仔细查看了 LinuxFileSystem.java and WindowsFileSystem.java,似乎在 windows 上检查了 /
和 \
字符的路径(在 WindowsPathParser.isSlash(char c)
方法)。 Linux 实现不应该做同样的事情吗?
这是 sun.nio.fs.LinuxFileSystem
实现中的错误还是我做错了什么?
您还知道任何其他方法来确保 Linux 路径被正确解析和规范化(无需手动进行所有解析)。
在 Windows 中,/
不是文件名中的有效字符,因此任何代码都可以假定它是错误键入的路径分隔符。
在 Linux 中,文件名中几乎可以接受任何字节。在您的 Paths.get()
中,您有效地加入了一条名为 dir1
的路径(1 级深)和一条名为 \dir2\file1
的路径(也是 1 级深)。
Java on Windows 是根据 Microsoft C++ 标准库编译的,它允许反斜杠或正斜杠作为有效的路径分隔符。所以反斜杠只有在 Windows 上 运行 时才是有效的路径分隔符,而正斜杠在任何地方都有效。
唯一一次需要反斜杠,即使在 Windows 上也是如此,这是在创建将传递给 CMD.EXE、PowerShell 以及可能的其他 terminals/shells 的命令行时。还有一些开源库要求在文件路径中使用反斜杠(当 运行 on Windows 时),但 java 本身允许在文件路径中使用正斜杠或反斜杠。
恕我直言,在解析输入时使用 File.separator 通常会导致可避免的错误,而在生成供软件或人眼使用的输出时它具有有效的作用。
我目前正在编写一些代码,其中我经常使用文件。我使用 Java 7 nio classes 路径和路径实现了所有文件路径处理(连接、规范化等)。在 Windows 上,一切都按预期工作,但是在 Linux 上,路径 class 行为似乎被破坏了。
例如下面的代码:
System.out.println(File.separator);
System.out.println(FileSystems.getDefault());
Path path = Paths.get("../dir1/", "\dir2\file1").toAbsolutePath().normalize();
System.out.println(path);
if(path.toFile().exists()) {
System.out.println(path + " exists");
}
on Windows 打印以下输出:
\
sun.nio.fs.WindowsFileSystem
D:\projects\dir1\dir2\file1
true
但 Linux Ubuntu 14.04 上的代码相同 Java 1.7.0_79(64 位)和 Java 1.8.0_60(64 位)使路径未规范化:
/
sun.nio.fs.LinuxFileSystem
/home/semi/dir1/\dir2\file1
此外,即使文件位于路径 /home/semi/dir1/dir2/file1
中,它也被 path.toFile().exists()
报告为不存在。
我仔细查看了 LinuxFileSystem.java and WindowsFileSystem.java,似乎在 windows 上检查了 /
和 \
字符的路径(在 WindowsPathParser.isSlash(char c)
方法)。 Linux 实现不应该做同样的事情吗?
这是 sun.nio.fs.LinuxFileSystem
实现中的错误还是我做错了什么?
您还知道任何其他方法来确保 Linux 路径被正确解析和规范化(无需手动进行所有解析)。
在 Windows 中,/
不是文件名中的有效字符,因此任何代码都可以假定它是错误键入的路径分隔符。
在 Linux 中,文件名中几乎可以接受任何字节。在您的 Paths.get()
中,您有效地加入了一条名为 dir1
的路径(1 级深)和一条名为 \dir2\file1
的路径(也是 1 级深)。
Java on Windows 是根据 Microsoft C++ 标准库编译的,它允许反斜杠或正斜杠作为有效的路径分隔符。所以反斜杠只有在 Windows 上 运行 时才是有效的路径分隔符,而正斜杠在任何地方都有效。
唯一一次需要反斜杠,即使在 Windows 上也是如此,这是在创建将传递给 CMD.EXE、PowerShell 以及可能的其他 terminals/shells 的命令行时。还有一些开源库要求在文件路径中使用反斜杠(当 运行 on Windows 时),但 java 本身允许在文件路径中使用正斜杠或反斜杠。
恕我直言,在解析输入时使用 File.separator 通常会导致可避免的错误,而在生成供软件或人眼使用的输出时它具有有效的作用。