繁体   English   中英

Java 1.4.2 File.listFiles无法与CIFS挂载一起正常使用-解决方法?

[英]Java 1.4.2 File.listFiles not working properly with CIFS mounts - workaround?

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

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

它总是返回0 ,表示listFiles返回的File[]为空。 相同的问题适用于/mnt/share/每个子目录。 list返回空数组。 足够有趣的是,其他File功能(例如“创建”,“ isDirectory”或什至“删除”)也可以正常工作。 从USB闪存驱动器(fat32)挂载的目录也可以正常工作。

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

我想在程序中删除目录,除递归地遍历listFiles之外,目前没有其他方法可以执行此操作,因此此错误变得很烦人。 我唯一想到的“解决方法”是以某种方式运行外部bash脚本,但这似乎是一个糟糕的解决方案。

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

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

Java 1.2 ,提供了File.getCanonicalFile()方法。 对于挂载目录的情况,您应该以这种方式完全使用此目录:

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

因此,在放弃两年半之后,我遇到了同样的问题,再次陷入1.4.2的困境,因为我需要将代码嵌入到过时的Oracle Forms 10g版本中。

如果有人偶然发现了这个问题并决定适当地解决它,而不是破解它,那么它很可能与CIFS在挂载远程文件系统时所做的(高度)异常的inode映射有关,从而导致了一些更模糊的错误其中可以在serverfault上找到。 这种映射的副作用之一是所有目录的硬链接数均为零。 另一个是所有目录的“大小”都完全为0,而不是通常的“扇区大小或更大”,甚至可以使用ls进行检查。

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

无论如何,第二个副作用可以用来围绕File创建一个简单的包装,除非怀疑使用CIFS挂载目录,否则它不会依赖系统调用。 java.io.File其他版本的listlistFiles函数,甚至使用过滤器的版本,都在内部依赖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;
           }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM