1

我正在使用 Java 1.4.2 和 Debian 6.0.3。网络中有一个共享的 Windows 文件夹,它/mnt/share/使用 CIFS 通过 fstab 正确安装(例如,它在操作系统中完全可见并允许所有操作)。但是,当我尝试在 Java 中执行此操作时:

System.out.println(new File("/mnt/share/").listFiles().length)

它总是 return 0,这意味着File[]返回的listFiles是空的。同样的问题适用于/mnt/share/. list也返回空数组。有趣的是,File“create”、“isDirectory”甚至“delete”等其他功能都可以正常工作。从 USB 闪存驱动器 (fat32) 安装的目录也可以正常工作。

我在来自不同 Windows 系统的 2 个不同的“共享文件夹”上对此进行了测试;一种使用基于域的身份验证系统,另一种使用“简单共享”——即访客访问。这种情况看起来很奇怪,因为挂载的目录应该成为文件系统的一部分,所以任何程序都可以使用它。至少我是这么认为的。

我想在我的程序中删除一个目录,我目前看不到除了递归行走之外没有其他方法listFiles,所以这个错误变得相当烦人。我能想到的唯一“解决方法”是以某种方式运行外部 bash 脚本,但这似乎是一个糟糕的解决方案。

编辑:这似乎是 1.4.2 特有的错误,在 Java 6 中一切正常。但我无法迁移,所以问题仍然存在。

你能建议一些解决方法吗?最好不要切换到第三方库而不是本地库,我不能说我喜欢为了单个代码行而重写整个项目的想法。

4

2 回答 2

0

既然Java 1.2有方法File.getCanonicalFile()。在您的安装目录的情况下,您应该以这种风格使用这个:

new File("/mnt/share/").getCanonicalFile().listFiles()

于 2014-03-25T08:19:19.697 回答
0

所以,在放弃两年半后,我遇到了同样的问题,再次坚持使用 1.4.2,因为我需要将代码嵌入到过时的 Oracle Forms 10g 版本中。

如果有人偶然发现这个问题并决定正确解决它,而不是破解他的方式,它很可能与 CIFS 在安装远程文件系统时所做的(高度)不寻常的 inode 映射有关,从而导致一些更模糊的错误其中可以在 serverfault 上找到。这种映射的副作用之一是所有目录的硬链接计数为零。另一个是所有目录的“大小”正好为 0,而不是通常的“扇区大小或更大”,即使使用ls.

如果不检查(专有)源代码,我无法确定,但我可以猜测 1.5 之前的 Java 使用了一些快捷方式,比如在内部检查链接计数,而不是用 C 实际调用 readdir(),这对于任何安装的 FS 都同样适用.

无论如何,第二个副作用可用于创建一个简单的 File 包装器,它不会依赖系统调用,除非它怀疑目录是使用 CIFS 安装的。中的其他版本listlistFiles函数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;
           }
    }
}
于 2015-01-05T08:40:36.607 回答