加快文件系统访问速度?

时间:2009-12-18 18:05:31

标签: java filesystems

我的应用扫描文件系统的一部分,我的用户报告说扫描网络驱动器时速度非常慢。在测试我的代码时,我发现了瓶颈:方法File.isFile()File.isDirectory()File.isHidden(),它们都在调用fs.getBooleanAttributes(File f)。在Windows网络驱动器上,此方法似乎非常慢。如何提高性能?我可以避免以某种方式调用此方法吗?

5 个答案:

答案 0 :(得分:10)

防御性代码通常会调用那些isXYZ()方法,这通常是一种很好的做法。但是,正如您所发现的那样,有时表现很差。

另一种方法是假设文件是​​文件,存在,可见,可读等,只是尝试阅读它。如果它不是那些东西,你会得到一个例外,你可以捕获,然后做检查,找出到底出了什么问题。这样,您就可以针对常见情况进行优化(即一切正常),并且只在出现问题时执行慢速操作。

答案 1 :(得分:6)

您是如何构建此文件列表的?除非您同时在系统上显示每个文件,否则您应该有一些选项......

  1. 仅在用户要求时处理此信息。例如他们点击文件夹“Windows”,此时您可以在Windows中处理文件。
  2. 在后台线程中处理此信息,从而产生更好的响应时间。
  3. 也许如果您显示用于构建列表的代码,我们可以找到其他一些改进方面。 (为什么你不能根据用于收集信息的方法推断出类型?如果你正在调用GetFiles()之类的方法,你不知道返回的所有内容都是文件吗?)

答案 2 :(得分:3)

我遇到了完全相同的问题

我们案例的解决方案非常简单:因为我们的目录结构遵循标准(没有名称中包含'。'字符的目录),我只是遵循标准,并应用了一个非常简单的启发式: “在我们的例子中,目录没有'。'它的名字中的字符“。这个简单的启发式方法大大减少了我们的应用程序调用java.io.File类的isDirectory()函数的次数。

也许这是你的情况。也许在您的目录结构中,您可以通过它的命名约定知道文件是否是一个目录。

答案 3 :(得分:2)

这是使用listFiles并使用isDirectory遍历目录树的前后代码示例(我的代码使用通用回调实际对每个目录和文件执行某些操作;如果我正在编码C#这将是一个代表。)

正如您所看到的,listFiles方法实际上更紧凑且易于理解,并且在本地驱动器(950毫秒vs 1000毫秒)和LAN驱动器(26秒,相对于28秒)上稍微快一点,共有23000个文件。

很可能对于远程连接的驱动器而言,加速可能很大,但我无法从工作中测试。有点令人惊讶的是,Windows RAS的加速仍然只有10%左右VPN到网络驱动器。

新代码

static public int processDirectory(File dir, Callback cbk, FileSelector sel) {
    dir=dir.getAbsoluteFile();
    return _processDirectory(dir.getParentFile(),dir,new Callback.WithParams(cbk,2),sel);
    }

static private int _processDirectory(File par, File fil, Callback.WithParams cbk, FileSelector sel) {
    File[]                              ents=(sel==null ? fil.listFiles() : fil.listFiles(sel));    // listFiles returns null if fil is not a directory
    int                                 cnt=1;

    if(ents!=null) {
        cbk.invoke(fil,null);
        for(int xa=0; xa<ents.length; xa++) { cnt+=_processDirectory(fil,ents[xa],cbk,sel); }
        }
    else {
        cbk.invoke(par,fil);                                                    // par can never be null
        }
    return cnt;
    }

旧代码

static public int oldProcessDirectory(File dir, Callback cbk, FileSelector sel) {
    dir=dir.getAbsoluteFile();
    return _processDirectory(dir,new Callback.WithParams(cbk,2),sel);
    }

static private int _processDirectory(File dir, Callback.WithParams cbk, FileSelector sel) {
    File[]                              ents=(sel==null ? dir.listFiles() : dir.listFiles(sel));
    int                                 cnt=1;

    cbk.invoke(dir,null);

    if(ents!=null) {
        for(int xa=0; xa<ents.length; xa++) {
            File                        ent=ents[xa];

            if(!ent.isDirectory()) {
                cbk.invoke(dir,ent);
                ents[xa]=null;
                cnt++;
                }
            }
        for(int xa=0; xa<ents.length; xa++) {
            File                        ent=ents[xa];

            if(ent!=null) {
                cnt+=_processDirectory(ent,cbk,sel);
                }
            }
        }
    return cnt;
    }

答案 4 :(得分:0)

如果您还没有尝试过,如果您对同一个文件执行多次检查,那么自己调用getBooleanAttributes并执行必要的屏蔽将会快得多。虽然不是一个完美的解决方案(并且开始将您的代码推向特定平台),但它可以将性能提高3或4倍。这是一个非常显着的性能提升,即使它不如它快得多应该是。

JDK7 java.nio.file.Path功能应该可以帮助解决这个问题。

最后,如果您对最终用户环境有任何控制权,请建议您的用户将其防病毒软件配置为不扫描网络驱动器。许多大型AV解决方案(不确定他们正在解决的问题)默认情况下会启用此功能。我不知道这会对各种File方法产生什么影响,但我们发现不正确配置的anit-virus几乎可以在网络资源上的每种文件访问中引起大量延迟问题。

相关问题