我试图了解Java在创建File
对象时解析相对路径的方式。
使用的操作系统:Windows
对于以下代码段,我收到IOException
,因为它无法找到路径:
@Test
public void testPathConversion() {
File f = new File("test/test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
我的理解是,Java将提供的路径视为绝对路径,并在路径不存在时返回错误。所以这很有道理。
当我更新上面的代码以使用相对路径时:
@Test
public void testPathConversion() {
File f = new File("test/../test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
它会创建一个新文件并提供以下输出:
test\..\test.txt
C:\JavaForTesters\test\..\test.txt
C:\JavaForTesters\test.txt
在这种情况下,我的假设是,即使提供的路径不存在,因为路径包含“/../”,java将其视为相对路径并在user.dir
中创建文件。所以这也是有道理的。
但如果我更新相对路径如下:
@Test
public void testPathConversion() {
File f = new File("test/../../test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
然后我得到IOException:访问被拒绝。
我的问题是:
"test/../test.txt"
被视为相对路径并在"user.dir"
中创建文件,但"test/../../test.txt"
会返回错误?它在哪里尝试为路径"test/../../test.txt"
创建文件?当找不到指定的相对路径时,该文件似乎是在user.dir
中创建的。所以,在我看来,下面两个场景做了同样的事情:
//scenario 1
File f = new File("test/../test.txt");
f.createNewFile();
//scenario 2
File f = new File("test.txt");
f.createNewFile();
那么有一个真实世界的情况,人们会使用场景1而不是场景2吗?
我想我错过了一些明显的东西,或者从根本上误解了相对路径。我浏览了文档的Java文档,但我无法找到解释。 Stack Overflow中有很多关于相对路径的问题,但我查找的是针对特定场景而不是关于如何解析相对路径的问题。
如果有人可以解释一下这是如何运作的,或者指向某些相关链接,那将会很棒吗?
答案 0 :(得分:20)
有working directory
的概念
该目录由.
(点)表示
在相对路径中,其他一切都与它相关。
只需将.
(工作目录)放在运行程序的位置即可。
在某些情况下,工作目录可以更改,但通常这是
点代表什么。我认为这是C:\JavaForTesters\
。
所以test\..\test.txt
表示:子目录test
在我的工作目录中,然后一级,然后是
档案test.txt
。这与test.txt
基本相同。
有关详情,请点击此处。
http://docs.oracle.com/javase/7/docs/api/java/io/File.html
http://docs.oracle.com/javase/tutorial/essential/io/pathOps.html
答案 1 :(得分:9)
当您的路径以根目录开头,即Windows中的C:\
或Unix中的/
或java资源路径中的路径时,它被视为绝对路径。其他一切都是相对的,所以
new File("test.txt") is the same as new File("./test.txt")
new File("test/../test.txt") is the same as new File("./test/../test.txt")
getAbsolutePath
和getCanonicalPath
之间的主要区别在于,第一个连接父路径和子路径,因此它可能包含点:..
或.
。 getCanonicalPath
将始终为特定文件返回相同的路径。
注意:File.equals
使用路径的抽象形式(getAbsolutePath
)来比较文件,这意味着相同的两个File
对象可能不相等而{{1}在File
或Map
等集合中使用是不安全的。
答案 2 :(得分:5)
工作目录是几乎所有操作系统和程序语言等的通用概念。它是程序运行的目录。这通常(但并非总是如此,有更改方法)应用程序所在的目录。
相对路径是在没有驱动器说明符的情况下启动的路径。所以在Linux中,它们不是以/
开头,在Windows中它们不是以C:\
开头等等。这些始终从您的工作目录开始。
绝对路径是以驱动器(或网络路径的机器)说明符开头的路径。它们总是从那个驱动器开始。
答案 3 :(得分:1)
如果您了解Java如何运行程序,则可以最好地理解相对路径。
在Java中运行程序时,有一个工作目录的概念。假设您有一个类,比如,/User/home/Desktop/projectRoot/src/topLevelPackage/
执行IO
java
。
根据您调用projectRoot
来运行程序的情况,您将拥有不同的工作目录。如果从内部和IDE运行程序,它很可能是$ projectRoot/src : java topLevelPackage.FileHelper
。
在这种情况下src
它将是$ projectRoot : java -cp src topLevelPackage.FileHelper
。
在这种情况下projectRoot
它将是$ /User/home/Desktop : java -cp ./projectRoot/src topLevelPackage.FileHelper
。
在这种情况下Desktop
它将是(Assuming $ is your command prompt with standard Unix-like FileSystem. Similar correspondence/parallels with Windows system)
。
(.)
因此,您的相对路径根package topLevelPackage
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileHelper {
// Not full implementation, just barebone stub for path
public void createLocalFile() {
// Explicitly get hold of working directory
String workingDir = System.getProperty("user.dir");
Path filePath = Paths.get(workingDir+File.separator+"sampleFile.txt");
// In case we need specific path, traverse that path, rather using . or ..
Path pathToProjectRoot = Paths.get(System.getProperty("user.home"), "Desktop", "projectRoot");
System.out.println(filePath);
System.out.println(pathToProjectRoot);
}
}
将解析为您的工作目录。因此,为了更好地确定在何处编写文件,它会考虑采用以下方法。
isatty(STDIN_FILENO)
希望这有帮助。
答案 4 :(得分:1)
我摆脱了peter.petrov的回答,但让我解释一下在何处进行文件编辑以将其更改为相对路径。
只需编辑“ AXLAPIService.java”并更改
url = new URL("file:C:users..../schema/current/AXLAPI.wsdl");
到
url = new URL("file:./schema/current/AXLAPI.wsdl");
或您想存储它的任何地方。
您仍然可以将wsdl文件打包到jar中的meta-inf文件夹中,但这是使它对我有用的最简单方法。
答案 5 :(得分:0)
只是与问题略有关系,但试着围绕这个问题。如此不直观:
import java.nio.file.*;
class Main {
public static void main(String[] args) {
Path p1 = Paths.get("/personal/./photos/./readme.txt");
Path p2 = Paths.get("/personal/index.html");
Path p3 = p1.relativize(p2);
System.out.println(p3); //prints ../../../../index.html !!
}
}