在Linux NFS上检查文件存在的任何确定的火灾方式?

时间:2011-09-22 03:06:35

标签: java linux nfs

我正在开发一个需要检查文件是否存在的Java程序。

嗯,很简单,代码使用File.exists()调用来检查文件是否存在。我遇到的问题是,它报告误报。这意味着该文件实际上并不存在,但exists()方法返回true。没有捕获异常(至少没有像“Stale NFS handle”那样的异常)。该程序甚至设法通过InputStream读取文件,按预期获得0个字节,但没有异常。目标目录是Linux NFS。而且我100%确定所查找的文件永远不会存在。

我知道java.io.File.exists()存在已知的错误(一种API限制)。因此,我通过使用Linux命令“ls”检查文件存在,然后添加了另一种方法。现在,Java代码不再调用File.exists(),而是运行Linux命令来“命中”目标文件。如果退出代码为0,则文件存在。否则,文件不存在。

随着技巧的引入,问题被击中的次数似乎有所减少,但仍然会爆发。同样,没有任何错误被捕获(stdout这次)。这意味着问题非常严重,即使本机Linux命令也无法在100%的时间内修复。

所以有几个问题围绕着:

  1. 我认为Java在File.exists()上众所周知的问题是关于报告误报。据报道文件不存在但实际上确实存在。由于API不会为File.exists()抛出IOException,因此在调用OS的底层本机函数失败的情况下,它会选择吞下Exception。 NFS超时。但是,鉴于该文件从未存在,这并不能解释我所遇到的误报。有没有抛出这个?
  2. 我对Linux“ls”退出代码的理解是,0表示没问题,相当于文件存在。这种理解是错的吗? “ls”的手册页在解释退出代码的含义时并不是那么清楚:退出状态为0如果正常则为1,如果是轻微问题则为2,如果是严重问题则为2。
  3. 好的,回到主题。在Linux上用Java检查File存在的任何万无一失的方法?在我们看到JDK7与NIO2正式发布之前。
  4. 谢谢:)

3 个答案:

答案 0 :(得分:0)

如果您需要健壮,请尝试读取文件 - 如果文件不存在(或存在权限或其他问题),则会正常失败。这也适用于除Java之外的任何其他语言。

判断文件是否存在并且可以从中读取的唯一安全方法是实际读取文件中的数据。无论文件系统如何 - 本地或远程。原因是竞争条件可能在您从checkAccess(path)获得成功后立即发生:检查,然后打开文件,您发现它突然不存在。某些其他线程(或其他远程客户端)可能已将其删除,或已获得独占锁定。所以不要打扰检查访问,而是尝试读取文件。花费时间运行ls只会让比赛条件窗口更容易适应。

答案 1 :(得分:0)

这是一个JUnit测试,显示问题和一些实际尝试读取文件的Java代码。

出现问题,例如在OSX Mavericks上使用Samba。可能的原因 在以下声明中解释:      http://appleinsider.com/articles/13/06/11/apple-shifts-from-afp-file-sharing-to-smb2-in-os-x-109-mavericks

它积极地缓存文件和文件夹属性,并使用机会锁定来更好地缓存数据。

请在下面找到一个checkFile,它实际上会尝试读取几个字节并强制进行真正的文件访问以避免缓存错误行为......

JUnit测试:

/**
 * test file exists function on Network drive replace the testfile name and ssh computer
     * with your actual environment
 * @throws Exception
 */
@Test
public void testFileExistsOnNetworkDrive() throws Exception {
    String testFileName="/Volumes/bitplan/tmp/testFileExists.txt";
    File testFile=new File(testFileName);
    testFile.delete();
    for (int i=0;i<10;i++) {
        Thread.sleep(50);
        System.out.println(""+i+":"+OCRJob.checkExists(testFile));
        switch (i) {
        case 3:
            // FileUtils.writeStringToFile(testFile, "here we go");
            Runtime.getRuntime().exec("/usr/bin/ssh phobos /usr/bin/touch "+testFileName);
            break;
        }
    }
}

checkExists源代码:

/**
 * check if the given file exists
 * @param f
 * @return true if file exists
 */
public static boolean checkExists(File f)  {
    try {
        byte[] buffer = new byte[4];
        InputStream is = new FileInputStream(f);
        if (is.read(buffer) != buffer.length) { 
            // do something 
        }
        is.close();
        return true;
    } catch (java.io.IOException fnfe) {

    }
    return false;
}

答案 2 :(得分:-1)

JDK7几个月前发布了。 Files类中有exists和notExists方法但它们返回一个布尔值而不是抛出异常。如果你真的想要一个异常,那么使用FileSystems.getDefault()。provider()。checkAccess(path),如果文件不存在,它将抛出异常。