我有一个包含大约300万个文件的目录。每天一次,我需要运行一个进程,创建一个单独的文件,其中包含该扩展名为.html
的大型目录中的文件名。通常,在那里的300万个文件中,500,000个将具有.html
扩展名。我使用以下内容:
find dirname -name "*.html"
但是,它会在完成前运行大约3个小时。有更快的方法吗?
更新:我用Perl和Java做了一些测试。使用Perl获取此目录的内容并创建.html
文件我尝试了以下(注意时间):
my @files = </$dirname/*.html> # 45 minutes
当我使用Java尝试此操作时:
final File[] files = dirname.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".html");
}
});
与Perl或我能想到的任何Unix命令相比,Java如何在3分钟内完成此操作?
答案 0 :(得分:2)
默认文件glob()对文件列表进行排序;这就是为什么需要很长时间。
my @files = </$dirname/*.html> # 45 minutes
尝试直接阅读目录:
my @files = ();
opendir my $dh, $dirname or die "could not open $dirname: $!\n";
while( my $file = readdir $dh ){
push @files, $file if $file =~ /\.html$/;
}
closedir $dh or die "could not close $dirname: $!\n";
答案 1 :(得分:1)
你应该使用&#34; getdents&#34;取代ls / find
ls和几乎所有其他列出目录的方法(包括python os.listdir,find。)都依赖于libc readdir()。但是readdir()一次只能读取32K的目录条目,这意味着如果你在同一目录中有很多文件(即500M的目录条目),那么读取所有目录条目将花费很长的时间。 ,特别是在慢速磁盘上。对于包含大量文件的目录,您需要比依赖readdir()的工具更深入地挖掘。您需要直接使用getdents()系统调用,而不是libc中的辅助方法。
您可以使用here中的getdents()找到C代码列出文件:
为了快速列出目录中的所有文件,您需要进行两项修改。
首先,将缓冲区大小从X增加到5兆字节。
#define BUF_SIZE 1024*1024*5
然后修改主循环,在那里打印出有关目录中每个文件的信息,以跳过带有inode == 0的条目。我这样做是通过添加
if (dp->d_ino != 0) printf(...);
在我的情况下,我也只关心目录中的文件名,所以我也重写了printf()语句只打印文件名。
if(d->d_ino) printf("%sn ", (char *) d->d_name);
编译它(它不需要任何外部库,所以它非常简单)
gcc listdir.c -o listdir
现在运行
./listdir [directory with insane number of files]
答案 2 :(得分:0)
你可以使用下面的ls
\ls -U
-U不排序;按目录顺序列出条目