所以,在放弃两年半后,我遇到了同样的问题,再次坚持使用 1.4.2,因为我需要将代码嵌入到过时的 Oracle Forms 10g 版本中。
如果有人偶然发现这个问题并决定正确解决它,而不是破解他的方式,它很可能与 CIFS 在安装远程文件系统时所做的(高度)不寻常的 inode 映射有关,从而导致一些更模糊的错误其中可以在 serverfault 上找到。这种映射的副作用之一是所有目录的硬链接计数为零。另一个是所有目录的“大小”正好为 0,而不是通常的“扇区大小或更大”,即使使用ls
.
如果不检查(专有)源代码,我无法确定,但我可以猜测 1.5 之前的 Java 使用了一些快捷方式,比如在内部检查链接计数,而不是用 C 实际调用 readdir(),这对于任何安装的 FS 都同样适用.
无论如何,第二个副作用可用于创建一个简单的 File 包装器,它不会依赖系统调用,除非它怀疑目录是使用 CIFS 安装的。中的其他版本list
和listFiles
函数java.io.File
,即使是使用过滤器的,也依赖于list()
内部,所以只覆盖它是可以的。
我不在乎listFiles
返回,所以我File[]
没有FileEx[]
费心去覆盖它,但应该足够简单。ls
显然,该代码只能在具有方便命令的类 Unix 系统中工作。
package FSTest;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class FileEx extends File
{
public FileEx(String path)
{
super(path);
}
public FileEx(File f)
{
super(f.getAbsolutePath());
}
public String[] list()
{
if (this.canRead() && this.isDirectory())
{
/*
* Checking the length of dir is not the most reliable way to distinguish CIFS mounts.
* However, zero directory length generally indicates something unusual,
* so calling ls on it wouldn't hurt. Ordinary directories don't suffer any overhead this way.
* If this "zero-size" behavior is ever changed by CIFS but list() still won't work,
* it will be safer to call super.list() first and call this.listUsingExec if returned array has 0 elements.
* Though it might have serious performance implications, of course.
*/
if (this.length() > 0)
return super.list();
else
return this.listUsingExec();
}
else
return null;
}
private String[] listUsingExec()
{
Process p;
String command = "/bin/ls -1a " + this.getAbsolutePath();
ArrayList list = new ArrayList();
try
{
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
for (String line = reader.readLine(); line != null; line = reader.readLine())
{
if (!line.equalsIgnoreCase(".") && !line.equalsIgnoreCase(".."))
list.add(line);
}
String[] ret = new String[list.size()];
list.toArray(ret);
return ret;
}
catch (IOException e)
{
return null;
}
}
}