[英]Speeding up file system access?
我的应用扫描部分文件系统,我的用户报告说扫描网络驱动器时速度非常慢。 测试我的代码,我发现了瓶颈:方法File.isFile()
, File.isDirectory()
和File.isHidden()
,它们都调用fs.getBooleanAttributes(File f)
。 在Windows网络驱动器上,此方法似乎非常慢。 如何提高性能? 我可以避免以某种方式调用此方法吗?
防御性代码通常会调用那些isXYZ()
方法,这通常是很好的做法。 但是,正如您所发现的,有时性能很差。
另一种方法是假设文件是文件,存在,可见,可读等,只是尝试阅读它。 如果它不是那些东西,你会得到一个例外,你可以捕获,然后做检查,找出到底出了什么问题。 这样,你就可以针对常见情况进行优化(即一切都很好),并且只在出现问题时执行慢速操作。
你是如何建立这个文件列表的? 除非你同时在系统上显示每个文件,否则你应该有一些选择......
也许如果您显示用于构建列表的代码,我们可以找到其他一些改进的方面。 (为什么不能根据用于收集信息的方法推断出类型?如果你正在调用像GetFiles()这样的方法,你不知道返回的所有内容都是文件吗?)
我遇到了完全相同的问题
我们的案例的解决方案非常简单:因为我们的目录结构遵循标准(没有名称中包含'。'字符的目录),我只是遵循标准,并应用了一个非常简单的启发式:“在我们的case,目录没有'。' 它的名字中的字符“。 这种简单的启发式方法大大减少了我们的应用程序调用java.io.File类的isDirectory()函数的次数。
也许这是你的情况。 也许在您的目录结构中,您可以通过它的命名约定知道文件是否是目录。
这是一个前后代码示例,用于使用listFiles
并使用isDirectory
遍历目录树(我的代码使用通用回调实际对每个目录和文件执行某些操作;如果我编写C#,则这将是委托)。
正如您所看到的, listFiles
方法实际上更紧凑且易于理解,并且在本地驱动器(950毫秒与1000毫秒)和LAN驱动器(26秒,与28秒)之间略微更快,两者都有23000个文件。
对于远程连接的驱动器来说,加速可能很大,但我无法从工作中测试。
有点令人惊讶的是,从Windows RAS VPN到网络驱动器,加速仍然只有10%左右。
新规范
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;
}
如果您还没有尝试过,如果您对同一个文件执行多次检查,那么自己调用getBooleanAttributes并执行必要的屏蔽将会快得多。 虽然不是一个完美的解决方案(并且开始将您的代码推向特定平台),但它可以将性能提高3或4倍。这是一个非常显着的性能提升,即使它不如它快得多应该。
JDK7 java.nio.file.Path功能应该可以帮助解决这类问题。
最后,如果您对最终用户环境有任何控制权,请建议您的用户将其防病毒软件配置为不扫描网络驱动器。 许多大型AV解决方案(不确定他们正在解决的问题)默认情况下会启用此功能。 我不知道这会对各种File方法产生什么影响,但我们发现不正确配置的anit-virus几乎可以在网络资源上的每种文件访问中引起大量延迟问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.