【问题标题】:How does Java resolve a relative path in new File()?Java 如何解析 new File() 中的相对路径?
【发布时间】:2014-01-30 09:51:07
【问题描述】:

我试图了解 Java 在创建 File 对象时解析相对路径的方式。

使用的操作系统:Windows

对于下面的 sn-p,我得到一个 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: Access is denied.

我的问题是:

  1. 为什么"test/../test.txt"被视为相对路径并在"user.dir"中创建文件但"test/../../test.txt"返回错误?它在哪里尝试为路径 "test/../../test.txt" 创建文件?
  2. 当没有找到指定的相对路径时,文件似乎是在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 的情况?

我想我在这里遗漏了一些明显的东西,或者从根本上误解了相对路径。我浏览了 File 的 Java 文档,但找不到对此的解释。 Stack Overflow 中发布了很多关于相对路径的问题,但我查找的问题是针对特定场景的,而不是关于如何解决相对路径的问题。

如果有人能解释一下这是如何工作的或指向一些相关链接,那就太好了?

【问题讨论】:

  • 请注意,user.dir 是一个非常多变的地方,应用程序依赖它会很脆弱。另一个需要考虑的因素是应用程序。可能没有安装在它具有写入权限的位置。* 将文件放在user.home 的(子目录)中会更加优化和健壮。有关简短示例,请参阅 this answer
  • 注意:test/test.txttest/../test.txt 都是相对路径。这个意义上的相对与嵌入的..组件的存在无关。

标签: java file relative-path


【解决方案1】:

有一个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

【讨论】:

    【解决方案2】:

    当您的路径以根目录开头时,即 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")
    

    getAbsolutePathgetCanonicalPath 之间的主要区别在于第一个连接父路径和子路径,因此它可能包含点:...getCanonicalPath 将始终为特定文件返回相同的路径。

    注意:File.equals 使用抽象形式的路径 (getAbsolutePath) 来比较文件,因此这意味着相同的两个 File 对象可能不相等,Files 使用不安全MapSet 之类的集合。

    【讨论】:

      【解决方案3】:

      工作目录是几乎所有操作系统和程序语言等的通用概念。它是您的程序运行的目录。这通常是(但并非总是如此,有办法改变它)应用程序所在的目录。

      相对路径是在没有驱动器说明符的情况下开始的。所以在 linux 中它们不以 / 开头,在 Windows 中它们不以 C:\ 开头,等等。这些总是从您的工作目录开始。

      绝对路径是以驱动器(或网络路径的机器)说明符开头的路径。他们总是从那条路的起点出发。

      【讨论】:

        【解决方案4】:

        如果您知道 Java 如何运行程序,则可以最好地理解相对路径。

        在Java中运行程序时,有一个工作目录的概念。假设你有一个类,比如说,FileHelper,它在下面做 IO /User/home/Desktop/projectRoot/src/topLevelPackage/

        根据您调用java 运行程序的情况,您将拥有不同的工作目录。如果您从内部和 IDE 运行程序,它很可能是 projectRoot

        • 在这种情况下,$ 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);
        
            }
        }
        

        希望这会有所帮助。

        【讨论】:

          【解决方案5】:

          在 windows 和 Netbeans 上,您可以将相对路径设置为:

              new FileReader("src\\PACKAGE_NAME\\FILENAME");
          

          在 Linux 和 Netbeans 上,您可以将相对路径设置为:

              new FileReader("src/PACKAGE_NAME/FILENAME");
          

          如果您在Source Packages 中有您的代码 不知道eclipse或者其他IDE是不是也一样

          【讨论】:

            【解决方案6】:

            仅与该问题略微相关,但请尝试围绕这个问题。太不直观了:

            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  !!
              }
            }
            

            【讨论】:

              【解决方案7】:

              我离开了 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 文件夹中,但这是让它为我工作的最简单方法。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-05-09
                • 2015-12-26
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-09-15
                相关资源
                最近更新 更多