我的应用程序扫描文件系统的一部分,并且我的用户在扫描网络驱动器时报告它非常慢。测试我的代码,我发现了瓶颈:方法File.isFile()
,File.isDirectory()
和File.isHidden()
,它们都调用fs.getBooleanAttributes(File f)
。这种方法在Windows网络驱动器上似乎非常慢。我该如何提高性能?我能否以某种方式避免调用此方法?加速文件系统访问?
回答
你是如何建立这个文件列表?除非您同时在系统上显示每个文件,否则您应该有一些选项...
- 只有在用户请求时才处理此信息。例如他们点击文件夹“Windows”,此时您可以在Windows中处理文件。
- 在后台线程中处理此信息,给出更好的响应时间的错觉。
也许如果你展示你用来构建列表的代码,我们可以找到一些其他方面的改进。 (为什么不能根据用于收集信息的方法来推断类型?如果您调用GetFiles()这样的方法,您是否已经知道返回的所有内容都是文件?)
防御性代码通常会调用那些isXYZ()
方法,这是一种很好的做法。但是,正如你发现的那样,有时性能很差。
另一种方法是假定该文件是一个文件,它存在,它是可见的,可读的等,只是尝试和阅读它。如果不是那些东西,你会得到一个你可以捕捉到的异常,然后做检查以确定究竟出了什么问题。那样的话,你正在为常见情况进行优化(即一切正常),并且只在出现问题时才执行缓慢的操作。
呵呵。这是一个非常有趣的方式来看待这个问题,但不幸的是它不适用于我的情况。我在做的是构建一个镜像用户文件结构的树,所以我必须弄清楚File是一个文件还是一个目录。虽然,我想我可以使用listFiles()来作出区分......谢谢,你给了我一些想法! – 2009-12-18 18:14:47
+1我喜欢优化“常见案例”的观点。您仍然可以保留防御性检查以处理何时不是文件。 – mpeterson 2009-12-18 18:49:36
+1我只是修改了一些递归目录树处理代码,以使用listFiles来确定“文件”是否是一个目录;这对本地和局域网连接的驱动器来说只是一个小小的加速 - 我无法测试VPN远程驱动器,直到我回家。这也是更简洁的代码。 – 2009-12-19 00:33:21
I面对完全相同的问题
我们的解决方案非常简单:由于我们的目录结构遵循一个标准(其中没有名称中包含'。'字符的目录),所以我只遵循标准,应用了一个非常简单的启发式:“在我们的例子中,目录没有'。'字符在它的名字“。这种简单的启发式方法极大地减少了我们的应用程序必须调用java.io.File类的isDirectory()函数的次数。
也许这是你的情况。也许在你的目录结构中,你可以知道一个文件是否只是它的命名约定。
个人而言,我很不情愿编写依赖于“应该怎么做”的代码。并不是说这不是一个好的解决方案,但它很危险。如果有人不知道该标准或者出于任何原因不遵守标准,那么您的代码会给出不正确的结果。在错误的数据上给出错误信息是一回事,简直就是失败就是另一回事。 – Jay 2009-12-18 18:53:40
如果我有这样的标准依靠,那很好,但不幸的是我没有。 :o) – 2009-12-18 21:49:04
以下是使用listFiles和使用isDirectory来遍历目录树的代码示例(我的代码使用通用回调实际上对每个目录和文件执行某些操作;如果我编码C#,这将是一个委托) 。
正如您所看到的,listFiles方法实际上更加紧凑,易于理解,并且在本地驱动器(950毫秒vs 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病毒可能会在几乎所有网络资源上的文件访问中导致严重的延迟问题。
如果我可以自己调用getBooleanAttributes(),确实会更快,但不幸的是,我受限于Java 1.5,并且java.io.FileSystem受软件包保护!愚蠢的抽象障碍,一直困扰着你。 :o) – 2009-12-21 15:37:18
您应该能够使用反射来获取该方法(请参阅Method。setAccessible()) 可能工作的另一个技巧(我不确定如果jvm会拒绝java.io pacakge中的类,如果它们没有被Sun签名的话)将会创建属于同一个文件夹的自己的类(只需将它放入jar中的java.io文件夹中)。 – 2009-12-22 20:30:54
- 1. Xamarin.Android访问文件系统
- 2. java访问客户端文件系统
- 3. Azure Webjob - 访问本地文件系统
- 4. 调试文件系统访问
- 5. asp.net库访问android文件系统
- 6. 访问iOS的Mac文件系统
- 7. Xml /文件系统并发访问
- 8. 本地文件系统访问和PHP5
- 9. 从iOS访问OSX文件系统?
- 10. 保护码头文件系统访问
- 11. 访问铬沙盒文件系统
- 12. 访问客户端文件系统
- 13. 如何从Nuxt.js访问文件系统?
- 14. 模拟文件系统访问
- 15. iPhone移动Safari文件系统访问
- 16. JavaScript可以访问文件系统吗?
- 17. 访问根级系统文件夹Android
- 18. 试图从jenkinsfile访问文件系统
- 19. 从J2EE系统访问sharepoint文件
- 20. 如何从系统中访问系统jboss文件夹中的文件
- 21. 只读文件系统访问是否保证写访问?
- 22. 如何加速文件存储访问?
- 23. 访问android系统
- 24. 问题与文件系统android快速问题
- 25. iPhone/iPod文件系统的速度
- 26. 如何快速查询文件系统?
- 27. 如何访问“文件夹”,“文件”等系统图标?
- 28. 访问iphone文件系统和复制文件
- 29. 问题设置文件系统访问规则
- 30. 如何在java编程中从系统访问文件到另一个系统?
+1为一个简单的解决方案。 – wheaties 2009-12-18 18:35:30
+2 :) .......... – OscarRyz 2009-12-18 18:42:17
你是对的,我可能是懒惰的,只有当用户要求他们加载文件夹,但然后会有一个暂停每次用户试图打开一个新的文件夹,这可能会让整个树感觉呆滞。这是一个开始需要很长时间并且一直很慢的平衡......但也许它不会那么糟糕。我将不得不测试它。感谢您的想法! – 2009-12-18 21:48:01