我正在开发一个需要检查文件是否存在的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%的时间内修复。
所以有几个问题围绕着:
谢谢:)
答案 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)