我的应用扫描文件系统的一部分,我的用户报告说扫描网络驱动器时速度非常慢。在测试我的代码时,我发现了瓶颈:方法File.isFile()
,File.isDirectory()
和File.isHidden()
,它们都在调用fs.getBooleanAttributes(File f)
。在Windows网络驱动器上,此方法似乎非常慢。如何提高性能?我可以避免以某种方式调用此方法吗?
答案 0 :(得分:10)
防御性代码通常会调用那些isXYZ()
方法,这通常是一种很好的做法。但是,正如您所发现的那样,有时表现很差。
另一种方法是假设文件是文件,存在,可见,可读等,只是尝试阅读它。如果它不是那些东西,你会得到一个例外,你可以捕获,然后做检查,找出到底出了什么问题。这样,您就可以针对常见情况进行优化(即一切正常),并且只在出现问题时执行慢速操作。
答案 1 :(得分:6)
您是如何构建此文件列表的?除非您同时在系统上显示每个文件,否则您应该有一些选项......
也许如果您显示用于构建列表的代码,我们可以找到其他一些改进方面。 (为什么你不能根据用于收集信息的方法推断出类型?如果你正在调用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几乎可以在网络资源上的每种文件访问中引起大量延迟问题。