给定一个包含大约10万个小文件的目录(每个文件大约1kB)。 我需要获取这些文件的列表并对其进行迭代,以便查找具有相同名称但不同大小写的文件(这些文件位于Linux ext4 FS上)。 目前,我使用了这样的代码:
def similar_files_in_folder(file_path, folder, exclude_folders = false)
files = Dir.glob(file_path, File::FNM_CASEFOLD)
files_set = files.select{|f| f.start_with?(folder)}
return files_set unless exclude_folders
files_set.reject{|entry| File.directory? entry}
end
dir_entries = Dir.entries(@directory) - ['.', '..']
dir_entries.map do |file_name|
similar_files_in_folder(file_name, @directory)
end
这种方法的问题是该片段需要很多!!!时间到了。 我的系统大约需要几个小时。
还有另一种方法可以实现相同的目标,但在Ruby中要快得多吗?
限制:我无法在内存中加载文件列表,然后只是在小写的情况下比较名称,因为在@directory中会出现新文件。 所以,我需要在每次迭代时扫描@directory。
感谢任何提示。
答案 0 :(得分:2)
如果我正确理解你的代码,这已经返回了所有这些100k文件名的数组:
dir_entries = Dir.entries(@directory) - ['.', '..']
#=> ["foo.txt", "bar.txt", "BAR.txt", ...]
我会用小写文件名对这个数组进行分组:
dir_entries.group_by(&:downcase)
#=> {"foo.txt"=>["foo.txt"], "bar.txt"=>["bar.txt", "BAR.txt"], ... }
选择出现次数超过1次的那些:
dir_entries.group_by(&:downcase).select { |k, v| v.size > 1 }
#=> {"bar.txt"=>["bar.txt", "BAR.txt"], ...}
答案 1 :(得分:1)
我的评论意味着您可以在遍历文件系统时搜索字符串,而不是首先构建大量所有可能的文件,然后再搜索。我写了一些类似于linux find <path> | grep --color -i <pattern>
的东西,除了仅在basename中突出显示模式:
require 'find'
#find files whose basename matches a pattern (and output results to console)
def find_similar(s, opts={})
#by default, path is '.', case insensitive, no bash terminal coloring
opts[:verbose] ||= false
opts[:path] ||= '.'
opts[:insensitive]=true if opts[:insensitive].nil?
opts[:color]||=false
boldred = "\e[1m\e[31m\\1\e[0m" #contains an escaped \1 for regex
puts "searching for \"#{s}\" in \"#{opts[:path]}\", insensitive=#{opts[:insensitive]}..." if opts[:verbose]
reg = opts[:insensitive] ? /(#{s})/i : /(#{s})/
dir,base = '',''
Find.find(opts[:path]) {|path|
dir,base = File.dirname(path), File.basename(path)
if base =~ reg
if opts[:color]
puts "#{dir}/#{base.gsub(reg, boldred)}"
else
puts path
end
end
}
end
time = Time.now
#find_similar('LOg', :color=>true) #similar to find . | grep --color -i LOg
find_similar('pYt', :path=>'c:/bin/sublime3/', :color=>true, :verbose=>true)
puts "search took #{Time.now-time}sec"
示例输出(cygwin),但如果从cmd.exe运行也可以