代码之家  ›  专栏  ›  技术社区  ›  Aaron Digulla

File.exists()在使用Java 8.191的Windows 10上有时会出错

  •  19
  • Aaron Digulla  · 技术社区  · 7 年前

    我有一系列单元测试,其中包含如下代码:

    File file = new File("src/main/java/com/pany/Foo.java");
    assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());
    

    -DforkCount=0 . 具有 -DforkCount=1 ,它起作用了。

    到目前为止我尝试过的事情:

    • 该文件确实存在。Windows资源管理器、命令行(复制和粘贴)、文本编辑器、Cygwin都可以找到它并显示内容。这就是为什么我认为这不是许可问题。
    • 它不会被单元测试或其他任何东西修改。Git在过去两个月内没有显示任何修改。
    • 我检查了文件系统,它是干净的。
    • 我尝试过Java8的其他版本,即8u171和8u181。同样的问题。
    • 我在Cygwin和命令提示符下运行了Maven。同样的结果。
    • 重新启动:-)无效:-(

    更多详情:

    • 当我看到这个问题时,我开始在其他项目中看到“分叉的VM在没有正确告别的情况下终止了。VM崩溃或调用了System.exit?”。这就是我为什么尝试的原因 forkCount=0 这通常有助于找出分叉VM崩溃的原因。
    • 这是最近开始的,可能是在2018年10月Windows 10更新前后。在此之前,这些建筑已经坚如磐石了大约三年。我想我的机器在2017年末被切换到了Windows 10。
    • 我使用的是Maven 3.6,无法轻松尝试旧版本,因为它修复了一个重要的bug。我也看到了上面Maven 3.5.2的VM崩溃。

    ulimit

    $ ulimit -a
    core file size          (blocks, -c) unlimited
    data seg size           (kbytes, -d) unlimited
    file size               (blocks, -f) unlimited
    open files                      (-n) 256
    pipe size            (512 bytes, -p) 8
    stack size              (kbytes, -s) 2032
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 256
    virtual memory          (kbytes, -v) unlimited
    

    我想知道256的“打开文件”限制是否只适用于Cygwin进程,或者Cygwin是否从Windows读取这些文件。

    如果你还需要什么,请告诉我。我想不出我能尝试什么了。

    更新1

    Bernhard

    File file = new File("src/main/java/com/pany/Foo.java");
    if (!file.exists()) {
        log.debug("Missing file {}", file.getAbsolutePath());
        ... fail ...
    }
    
    ... do something with file...
    

    我现在将此更改为:

    File file = new File("src/main/java/com/pany/Foo.java").getAbsoluteFile();
    if (!file.exists()) {
        log.debug("Missing file {}", file);
    }
    

    这就解决了问题。我就是不明白 为什么? .

    exists() 解决问题?

    3 回复  |  直到 7 年前
        1
  •  8
  •   Aaron Digulla    7 年前

    一些背景。每个进程都有一个“当前目录”的概念。从命令行启动时,它就是执行命令的目录。从UI启动时,通常是程序(exe文件)所在的文件夹。

    在命令提示符或BASH中,可以使用 cd 用于运行命令提示符的进程。

    src/main/java/ user.dir .

    这就是为什么 new File("a").exists() new File("a").getAbsoluteFile().exists() 工作方式不同。

    后者将使用 new File(System.getProperty("user.dir"), "a") _wgetdcwd ( docs )这反过来又使用Windows进程的一个字段来获取当前目录——在我们的例子中,这始终是Maven最初启动的文件夹,因为当有人更改时,Java不会更新进程中的字段 user.dir

    WinNTFileSystem_md.c 电话 fileToNTPath() . 这是在 io_util_md.c 和电话 pathToNTPath() . 对于相对路径,它将调用 currentDirLength() 哪个叫 currentDir() 哪个叫 _wgetdcwd() .

    另见:

    user.dir https://github.com/apache/maven-surefire/blob/56d41b4c903b6c134c5e1a2891f9f08be7e5039f/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java#L1060

    https://github.com/apache/maven-surefire/blob/56d41b4c903b6c134c5e1a2891f9f08be7e5039f/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java#L1133

        2
  •  1
  •   khmarbaise    7 年前

    所以我 have checked via printing out the system properties with some simple tests .

    在通过maven surefire插件进行测试期间 user.dir 将更改为多模块生成中相应模块的根目录。

    但正如我已经提到的,有一个系统属性可用 basedir File 这个 巴塞迪尔 指的是 pom.xml 适当模块的名称。

    但不幸的是 巴塞迪尔 财产是 由IDEA IntelliJ在测试运行期间设置。

    但这可以通过如下设置来解决:

     private String basedir;
    
     @Before
     public void before() {
        this.basedir = System.getProperty("basedir", System.getProperty("user.dir", "Need to think about the default value"));
     }
    
     @Test
     public void testX() {
       File file = new File(this.basedir, "src/main/java/com/pany/Foo.java");
       assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());
     }
    

    -DforkCount=0 以及 -DforkCount=1 在IDE中(仅选中IDEA IntelliJ)。

    是的,这是Maven Surefire插件更改 user.dir .

    我们可以说服IDE支持 巴塞迪尔 财产也是吗?

        3
  •  0
  •   tibor17    7 年前

    Aaron,我们开发Surefire。如果您提供以下路径,我们可以帮助您:

    assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());
    

    请张贴实际路径、预期路径和 巴塞迪尔 您的POM所在的位置。 这个理论在这里没有帮助。我们正在测试JDKs7-12的所有频谱,但我们没有必须考虑的Cygwin+Windows组合。 user.dir 你提到的Surefire存在了十年。