我试图一次处理一个通过网络存储的文件.由于缓冲不是问题,因此读取文件很快.我遇到的问题只是列出文件夹中的目录.在许多文件夹中,每个文件夹至少有10k个文件.
由于File.list()返回数组而不是iterable,因此性能非常慢.Java关闭并收集文件夹中的所有名称,并在返回之前将其打包到数组中.
这个错误条目是http://bugs.sun.com/view_bug.do;jsessionid=db7fcf25bcce13541c4289edeb4?bug_id=4285834并且没有解决方法.他们只是说这已经为JDK7修复了.
几个问题:
有没有人解决这个性能瓶颈问题?
我想要实现不可能吗?即使它只是遍历目录,性能仍然会变差吗?
我可以使用测试版JDK7构建具有此功能,而无需建立在它在我的整个项目?
Bill K.. 7
虽然它不漂亮,但我通过在启动我的应用程序之前将dir/ls的输出传递给文件并传入文件名来解决这种问题.
如果你需要在应用程序中执行它,你可以使用system.exec(),但它会产生一些肮脏.
您询问.第一种形式将非常快,第二种形式也应该非常快.
确保每行执行一项(裸露,无装饰,无图形),完整路径并递归所选命令的选项.
编辑:
只需30分钟即可获得目录列表,哇.
让我感到震惊的是,如果你使用exec(),你可以将它的stdout重定向到管道而不是将其写入文件.
如果您这样做,您应该立即开始获取文件,并能够在命令完成之前开始处理.
这种互动实际上可能会减慢速度,但也许不会 - 你可能会尝试一下.
哇,我刚刚为你找到.exec命令的语法并遇到了这个,可能正是你想要的(它使用exec和"ls"列出一个目录并将结果传递到你的程序中进行处理): 良好的链接在韦巴克(约尔格在评论提供给替换这一个来自太阳,甲骨文爆发)
无论如何,这个想法是直截了当的,但正确的代码是令人讨厌的.我将从互联网中窃取一些代码并将其破解 - brb
/** * Note: Only use this as a last resort! It's specific to windows and even * at that it's not a good solution, but it should be fast. * * to use it, extend FileProcessor and call processFiles("...") with a list * of options if you want them like /s... I highly recommend /b * * override processFile and it will be called once for each line of output. */ import java.io.*; public abstract class FileProcessor { public void processFiles(String dirOptions) { Process theProcess = null; BufferedReader inStream = null; // call the Hello class try { theProcess = Runtime.getRuntime().exec("cmd /c dir " + dirOptions); } catch(IOException e) { System.err.println("Error on exec() method"); e.printStackTrace(); } // read from the called program's standard output stream try { inStream = new BufferedReader( new InputStreamReader( theProcess.getInputStream() )); processFile(inStream.readLine()); } catch(IOException e) { System.err.println("Error on inStream.readLine()"); e.printStackTrace(); } } // end method /** Override this method--it will be called once for each file */ public abstract void processFile(String filename); } // end class
谢谢IBM的代码捐赠者
虽然它不漂亮,但我通过在启动我的应用程序之前将dir/ls的输出传递给文件并传入文件名来解决这种问题.
如果你需要在应用程序中执行它,你可以使用system.exec(),但它会产生一些肮脏.
您询问.第一种形式将非常快,第二种形式也应该非常快.
确保每行执行一项(裸露,无装饰,无图形),完整路径并递归所选命令的选项.
编辑:
只需30分钟即可获得目录列表,哇.
让我感到震惊的是,如果你使用exec(),你可以将它的stdout重定向到管道而不是将其写入文件.
如果您这样做,您应该立即开始获取文件,并能够在命令完成之前开始处理.
这种互动实际上可能会减慢速度,但也许不会 - 你可能会尝试一下.
哇,我刚刚为你找到.exec命令的语法并遇到了这个,可能正是你想要的(它使用exec和"ls"列出一个目录并将结果传递到你的程序中进行处理): 良好的链接在韦巴克(约尔格在评论提供给替换这一个来自太阳,甲骨文爆发)
无论如何,这个想法是直截了当的,但正确的代码是令人讨厌的.我将从互联网中窃取一些代码并将其破解 - brb
/** * Note: Only use this as a last resort! It's specific to windows and even * at that it's not a good solution, but it should be fast. * * to use it, extend FileProcessor and call processFiles("...") with a list * of options if you want them like /s... I highly recommend /b * * override processFile and it will be called once for each line of output. */ import java.io.*; public abstract class FileProcessor { public void processFiles(String dirOptions) { Process theProcess = null; BufferedReader inStream = null; // call the Hello class try { theProcess = Runtime.getRuntime().exec("cmd /c dir " + dirOptions); } catch(IOException e) { System.err.println("Error on exec() method"); e.printStackTrace(); } // read from the called program's standard output stream try { inStream = new BufferedReader( new InputStreamReader( theProcess.getInputStream() )); processFile(inStream.readLine()); } catch(IOException e) { System.err.println("Error on inStream.readLine()"); e.printStackTrace(); } } // end method /** Override this method--it will be called once for each file */ public abstract void processFile(String filename); } // end class
谢谢IBM的代码捐赠者
如何使用File.list(FilenameFilter filter)方法并实现FilenameFilter.accept(File dir,String name)处理每个文件并返回false。
我在Linux vm上运行了包含10K +文件的目录,这花费了<10秒的时间。
import java.io.File; import java.io.FilenameFilter; public class Temp { private static void processFile(File dir, String name) { File file = new File(dir, name); System.out.println("processing file " + file.getName()); } private static void forEachFile(File dir) { String [] ignore = dir.list(new FilenameFilter() { public boolean accept(File dir, String name) { processFile(dir, name); return false; } }); } public static void main(String[] args) { long before, after; File dot = new File("."); before = System.currentTimeMillis(); forEachFile(dot); after = System.currentTimeMillis(); System.out.println("after call, delta is " + (after - before)); } }