是否存在File.getCanonicalPath()和File.toPath()。toRealPath()会产生不同结果的情况? 他们似乎做了两件相似的事情,但文档从来没有说明他们应该做同样的事情。 是否存在边界情况,我更喜欢一种方法而不是另一种方法? 那么File.getAbsolutePath()与Path.toAbsolutePath()相比,它们应该以相同的方式工作吗?
答案 0 :(得分:4)
结论:
getAboslutePath
和getPath
永远不会失败,因为他们不进行验证getCanonicalPath
会得到无效结果toPath().toRealPath()
正在检查有效性,但文件必须存在,并且可以跟随或不跟随符号链接 toPath()
足够安全,不需要文件存在。.toPath().toAbsolutePath().normalize()
是最好的文件,不需要文件 我在Windows中对@John进行了类似的测试
@Test
public void testCanonical() throws IOException {
test("d:tarGet\\..\\Target", "File exist and drive letter is on the current one");
test("d:tarGet\\..\\Target\\.\\..\\", "File exist and drive letter is on the current one, but parent of current drive should exist");
test("d:tarGet\\non-existent\\..\\..\\Target\\.\\..\\", "Relative path contains non-existent file");
test("d:target\\\\file", "Double slash");
test("c:tarGet\\..\\Target\\.", "File doesn't exist and drive letter is on different drive than the current one");
test("l:tarGet\\..\\Target\\.\\..\\", "Drive letter doesn't exist");
test("za:tarGet\\..\\Target\\.\\..\\", "Drive letter is double so not valid");
test("d:tarGet|Suffix", "Path contains invalid chars in windows (|)");
test("d:tarGet\u0000Suffix", "Path contains invalid chars in both linux and windows (\\0)");
}
private void test(String filename, String message) throws IOException {
java.io.File file = new java.io.File(filename);
System.out.println("Use: " + filename + " -> " + message);
System.out.println("F-GET: " + Try.of(() -> file.getPath()));
System.out.println("F-ABS: " + Try.of(() -> file.getAbsolutePath()));
System.out.println("F-CAN: " + Try.of(() -> file.getCanonicalPath()));
System.out.println("P-TO: " + Try.of(() -> file.toPath()));
System.out.println("P-ABS: " + Try.of(() -> file.toPath().toAbsolutePath()));
System.out.println("P-NOR: " + Try.of(() -> file.toPath().normalize()));
System.out.println("P-NOR-ABS: " + Try.of(() -> file.toPath().normalize().toAbsolutePath()));
System.out.println("P-ABS-NOR: " + Try.of(() -> file.toPath().toAbsolutePath().normalize()));
System.out.println("P-REAL: " + Try.of(() -> file.toPath().toRealPath()));
System.out.println("");
}
结果是:
Use: d:tarGet\..\Target -> File exist and drive letter is on the current one
F-GET: Success(d:tarGet\..\Target)
F-ABS: Success(d:\home\raiser\work\restfs\tarGet\..\Target)
F-CAN: Success(D:\home\raiser\work\restfs\target)
P-TO: Success(d:tarGet\..\Target)
P-ABS: Success(D:\home\raiser\work\restfs\tarGet\..\Target)
P-NOR: Success(d:Target)
P-NOR-ABS: Success(D:\home\raiser\work\restfs\Target)
P-ABS-NOR: Success(D:\home\raiser\work\restfs\Target)
P-REAL: Success(D:\home\raiser\work\restfs\target)
Use: d:tarGet\..\Target\.\..\ -> File exist and drive letter is on the current one, but parent of current drive should exist
F-GET: Success(d:tarGet\..\Target\.\..)
F-ABS: Success(d:\home\raiser\work\restfs\tarGet\..\Target\.\..)
F-CAN: Success(D:\home\raiser\work\restfs)
P-TO: Success(d:tarGet\..\Target\.\..)
P-ABS: Success(D:\home\raiser\work\restfs\tarGet\..\Target\.\..)
P-NOR: Success(d:)
P-NOR-ABS: Success(D:\home\raiser\work\restfs\)
P-ABS-NOR: Success(D:\home\raiser\work\restfs)
P-REAL: Success(D:\home\raiser\work\restfs)
Use: d:tarGet\non-existent\..\..\Target\.\..\ -> Relative path contains non-existent file
F-GET: Success(d:tarGet\non-existent\..\..\Target\.\..)
F-ABS: Success(d:\home\raiser\work\restfs\tarGet\non-existent\..\..\Target\.\..)
F-CAN: Success(D:\home\raiser\work\restfs)
P-TO: Success(d:tarGet\non-existent\..\..\Target\.\..)
P-ABS: Success(D:\home\raiser\work\restfs\tarGet\non-existent\..\..\Target\.\..)
P-NOR: Success(d:)
P-NOR-ABS: Success(D:\home\raiser\work\restfs\)
P-ABS-NOR: Success(D:\home\raiser\work\restfs)
P-REAL: Success(D:\home\raiser\work\restfs)
Use: d:target\\file -> Double slash
F-GET: Success(d:target\file)
F-ABS: Success(d:\home\raiser\work\restfs\target\file)
F-CAN: Success(D:\home\raiser\work\restfs\target\file)
P-TO: Success(d:target\file)
P-ABS: Success(D:\home\raiser\work\restfs\target\file)
P-NOR: Success(d:target\file)
P-NOR-ABS: Success(D:\home\raiser\work\restfs\target\file)
P-ABS-NOR: Success(D:\home\raiser\work\restfs\target\file)
P-REAL: Failure(java.nio.file.NoSuchFileException: D:\home\raiser\work\restfs\target\file)
Use: c:tarGet\..\Target\. -> File doesn't exist and drive letter is on different drive than the current one
F-GET: Success(c:tarGet\..\Target\.)
F-ABS: Success(c:\\tarGet\..\Target\.)
F-CAN: Success(C:\Target)
P-TO: Success(c:tarGet\..\Target\.)
P-ABS: Success(C:\tarGet\..\Target\.)
P-NOR: Success(c:Target)
P-NOR-ABS: Success(C:\Target)
P-ABS-NOR: Success(C:\Target)
P-REAL: Failure(java.nio.file.NoSuchFileException: C:\Target)
Use: l:tarGet\..\Target\.\..\ -> Drive letter doesn't exist
F-GET: Success(l:tarGet\..\Target\.\..)
F-ABS: Success(l:\tarGet\..\Target\.\..)
F-CAN: Success(L:\)
P-TO: Success(l:tarGet\..\Target\.\..)
P-ABS: Failure(java.io.IOError: java.io.IOException: Unable to get working directory of drive 'L')
P-NOR: Success(l:)
P-NOR-ABS: Failure(java.io.IOError: java.io.IOException: Unable to get working directory of drive 'L')
P-ABS-NOR: Failure(java.io.IOError: java.io.IOException: Unable to get working directory of drive 'L')
P-REAL: Failure(java.io.IOException: Unable to get working directory of drive 'L')
Use: za:tarGet\..\Target\.\..\ -> Drive letter is double so not valid
F-GET: Success(za:tarGet\..\Target\.\..)
F-ABS: Success(D:\home\raiser\work\restfs\za:tarGet\..\Target\.\..)
F-CAN: Success(D:\home\raiser\work\restfs)
P-TO: Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-ABS: Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-NOR: Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-NOR-ABS: Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-ABS-NOR: Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
P-REAL: Failure(java.nio.file.InvalidPathException: Illegal char <:> at index 2: za:tarGet\..\Target\.\..)
Use: d:tarGet|Suffix -> Path contains invalid chars in windows (|)
F-GET: Success(d:tarGet|Suffix)
F-ABS: Success(d:\home\raiser\work\restfs\tarGet|Suffix)
F-CAN: Failure(java.io.IOException: The filename, directory name, or volume label syntax is incorrect)
P-TO: Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-ABS: Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-NOR: Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-NOR-ABS: Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-ABS-NOR: Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
P-REAL: Failure(java.nio.file.InvalidPathException: Illegal char <|> at index 8: d:tarGet|Suffix)
答案 1 :(得分:3)
规范路径为absolute and unique,但在不同系统上具有不同含义。
规范路径名既是绝对路径名也是唯一路径名。 规范形式的精确定义取决于系统。
真正的路径是the actual path with respect to the system.您还必须传入,无论您是否处理符号链接,而canonicalPath
隐含处理它。
此方法的精确定义取决于实现,但通常它派生自此路径,这是一个绝对路径,它定位与此路径相同的文件,但名称元素表示目录和文件的实际名称。例如,文件系统上的文件名比较不区分大小写,然后名称元素表示实际情况下的名称。此外,生成的路径删除了冗余名称元素。
所以是的,这两种方法可以返回不同的东西,但它实际上取决于你的系统。如果您需要一些独特的内容,那么canonicalPath
是您最安全的选择,即使它不是Path
。
答案 2 :(得分:2)
当然,下面的例子显示了一些差异。如果文件不存在,getCanonicalPath也会抛出异常。
getCanonicalPath以规范或最简单的形式返回路径(来自http://www.merriam-webster.com/dictionary/canonical%20form)
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(getApplicationContext(),
"dish name is : " + dataprovider.getName(), Toast.LENGTH_SHORT).show();
答案 3 :(得分:1)
我从测试中注意到的是
如果文件不存在,Path.toRealPath()将抛出java.nio.file.NoSuchFileException(Javadoc:返回现有的真实路径文件)。
如果文件不存在,File.getCanonicalPath()不会抛出异常(如果文件不存在,它将只抛出IOException 文件名本身无效,其中包含'\ 0'字符。)
因此,如果您想在实际创建文件之前将其用于路径检查,那么前者将不合适。
你说对,两种方法的Javadoc都有点浅。
答案 4 :(得分:0)
API声明规范路径通常会删除冗余并解析符号链接等。
在UNIX计算机上尝试以下操作:
File file = new File("../test.txt"); // execute from /tmp/java/example
file.getAbsolutePath(); // evaluates to /tmp/java/example/../test.txt
file.getCanonicalPath(); // evaluates to /tmp/java/test.txt
文件和路径之间的区别在于Path是新NIO API的一部分,它具有许多改进并且更加灵活。
作为示例,您可以使用NIO交换文件系统的实现(请参阅https://github.com/google/jimfs),而java.io.File则强制您在主机文件系统上进行操作。