Java 有没有可靠的方法来检查Linux NFS上的文件存在?
我正在开发一个Java程序,需要检查文件是否存在 很简单,代码使用调用Java 有没有可靠的方法来检查Linux NFS上的文件存在?,java,linux,java-io,nfs,Java,Linux,Java Io,Nfs,我正在开发一个Java程序,需要检查文件是否存在 很简单,代码使用调用File.exists()来检查文件是否存在。我的问题是,它报告了假阳性。这意味着文件实际上不存在,但exists()方法返回true。未捕获任何异常(至少没有像“过时NFS句柄”这样的异常)。该程序甚至通过InputStream读取了文件,得到了预期的0字节,但没有异常。目标目录是Linux NFS。而且我百分之百确定正在查找的文件永远不存在 我知道java.io.File.exists()存在已知的bug(某种API限制)
File.exists()
来检查文件是否存在。我的问题是,它报告了假阳性。这意味着文件实际上不存在,但exists()
方法返回true
。未捕获任何异常(至少没有像“过时NFS句柄”这样的异常)。该程序甚至通过InputStream
读取了文件,得到了预期的0字节,但没有异常。目标目录是Linux NFS。而且我百分之百确定正在查找的文件永远不存在
我知道java.io.File.exists()
存在已知的bug(某种API限制)。因此,我添加了另一种方法,即使用Linux命令ls
检查文件是否存在。Java代码不再调用File.exists()
而是运行一个Linux命令来ls
目标文件。如果退出代码为0
,则文件存在。否则,文件不存在
随着该技巧的引入,问题被击中的次数似乎减少了,但仍然会突然出现。同样,在任何地方都没有捕获到错误(这次是stdout)。这意味着问题非常严重,即使是本机Linux命令也无法在100%的时间内修复
因此,这里有几个问题:
File.exists()
的众所周知的问题是关于报告假阴性。其中文件报告不存在,但事实上确实存在。由于API不会为File.exists()
抛出IOException
,因此在调用操作系统底层本机函数失败(例如NFS超时)的情况下,它会选择吞掉异常。但这并不能解释我的假阳性案例,因为这个文件根本不存在。这件有什么问题吗ls
退出代码的理解是,0
表示可以,相当于文件存在。这种理解是错误的吗?ls
的手册页对退出代码的含义解释不太清楚:退出状态为0
如果正常,1
如果出现小问题,2
如果出现严重故障JDK7是几个月前发布的。类中有
exists
和notExists
方法,但它们返回布尔值而不是引发异常。如果确实需要异常,请使用FileSystems.getDefault().provider().checkAccess(path)
,如果文件不存在,它将抛出异常。JDK7是几个月前发布的。类中有exists
和notExists
方法,但它们返回布尔值而不是引发异常。如果确实需要异常,请使用FileSystems.getDefault().provider().checkAccess(path)
,如果该文件不存在,它将引发异常。如果您需要健壮,请尝试读取该文件,如果该文件不存在(或者存在权限或其他问题),则正常读取失败。这也适用于Java以外的任何其他语言
判断文件是否存在并且您可以从中读取的唯一安全方法是从文件中实际读取数据。无论文件系统是本地还是远程。原因是在您从checkAccess(path)
中获得成功后,可能会出现竞争条件:检查,然后打开文件,您会突然发现它不存在。其他一些线程(或其他远程客户端)可能已将其删除,或已获取独占锁。因此,不要费心检查访问权限,而是尝试读取文件。花时间运行ls
只会使竞态条件窗口更容易适应。如果您需要健壮,请尝试读取文件-如果文件不存在(或者存在权限或其他问题),请优雅地失败。这也适用于Java以外的任何其他语言
判断文件是否存在并且您可以从中读取的唯一安全方法是从文件中实际读取数据。无论文件系统是本地还是远程。原因是在您从checkAccess(path)
中获得成功后,可能会出现竞争条件:检查,然后打开文件,您会突然发现它不存在。其他一些线程(或其他远程客户端)可能已将其删除,或已获取独占锁。因此,不要费心检查访问权限,而是尝试读取文件。花时间运行ls
只会使竞态条件窗口更容易适应。下面是一个JUnit测试,它显示了问题和一些实际尝试读取文件的Java代码
问题发生了,例如在OSX Mavericks上使用Samba。可能的原因
由以下语句解释:
它积极缓存文件和文件夹属性,并使用机会锁定来更好地缓存数据。
请在下面找到一个检查文件,它将实际尝试读取几个字节并强制进行真正的文件访问,以避免缓存错误行为
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;
}
}
}
/**
* 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;
}
下面是一个JUnit测试,它显示了问题和一些实际尝试读取文件的Java代码
问题发生了,例如在OSX Mavericks上使用Samba。可能的原因
由以下语句解释:
它积极缓存文件和文件夹属性,并使用机会锁定来更好地缓存数据。
请在下面找到一个检查文件,它将实际尝试读取几个字节并强制进行真正的文件访问,以避免缓存错误行为
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;
}
}
}
/**
* 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;
}
您是否在检查文件是否存在的同一过程中创建和删除文件?Y