【发布时间】:2010-12-17 20:38:19
【问题描述】:
我想使用 Ruby 从一个文件夹中获取所有文件名。
【问题讨论】:
标签: ruby file directory filenames
我想使用 Ruby 从一个文件夹中获取所有文件名。
【问题讨论】:
标签: ruby file directory filenames
您还可以使用
的快捷方式选项Dir["/path/to/search/*"]
如果您想在任何文件夹或子文件夹中查找所有 Ruby 文件:
Dir["/path/to/search/**/*.rb"]
【讨论】:
./... 而不是~/
./ 表示当前目录,而/ 是根挂载点,~/ 是用户的主目录。如果您将整个项目移到其他地方,第一个可以工作,但其他两个可能不会。
Dir.entries(folder)
示例:
Dir.entries(".")
来源:http://ruby-doc.org/core/classes/Dir.html#method-c-entries
【讨论】:
Dir#glob 可能已经被提及)没有什么可以阻止其他人发布一个非常好的答案。 '当然,我主要是一个“玻璃杯半满”的人......
Dir,每次需要时我都必须阅读文档。我已经在这里发布了我的问题和答案,以便我以后可以找到它,甚至可以帮助有同样问题的人。我想我在 SO 播客上听说这种行为没有错。如果您有更好的答案,请发布。我已经发布了我所知道的,我不是 Ruby 忍者。我经常接受得票最多的答案。
Dir[] 或Dir.glob 更好的选择。当path = '/tmp' 时,比较:Dir.glob("#{path}/*") 与Dir.entries(path)。返回值略有不同(“.”、“..”),但后者更容易快速浏览。
下面的 sn-ps 准确显示了目录中的文件名,跳过了子目录和"."、".." 虚线文件夹:
Dir.entries("your/folder").select { |f| File.file? File.join("your/folder", f) }
【讨论】:
...select {|f| File.file? f} 以获得更清晰的含义和更短的语法。
Dir.entries("your/folder").select {|f| File.file? f}
!File.directory? 正在工作,但 File.file? 没有。
.reject {|f| File.directory? f} 似乎比 .select{|f| !File.directory? f} 干净。哦,现在我看到了第一条评论……也不错。
递归获取所有文件(仅限文件):
Dir.glob('path/**/*').select { |e| File.file? e }
或者任何不是目录的东西(File.file? 会拒绝非常规文件):
Dir.glob('path/**/*').reject { |e| File.directory? e }
使用Find#find 而不是像Dir.glob 这样的基于模式的查找方法实际上更好。见this answer to "One-liner to Recursively List Directories in Ruby?"。
【讨论】:
这对我有用:
如果您不想隐藏文件[1],请使用 Dir[]:
# With a relative path, Dir[] will return relative paths
# as `[ './myfile', ... ]`
#
Dir[ './*' ].select{ |f| File.file? f }
# Want just the filename?
# as: [ 'myfile', ... ]
#
Dir[ '../*' ].select{ |f| File.file? f }.map{ |f| File.basename f }
# Turn them into absolute paths?
# [ '/path/to/myfile', ... ]
#
Dir[ '../*' ].select{ |f| File.file? f }.map{ |f| File.absolute_path f }
# With an absolute path, Dir[] will return absolute paths:
# as: [ '/home/../home/test/myfile', ... ]
#
Dir[ '/home/../home/test/*' ].select{ |f| File.file? f }
# Need the paths to be canonical?
# as: [ '/home/test/myfile', ... ]
#
Dir[ '/home/../home/test/*' ].select{ |f| File.file? f }.map{ |f| File.expand_path f }
现在,Dir.entries 将返回隐藏文件,并且您不需要通配符 asterix(您可以只传递带有目录名称的变量),但它会直接返回基本名称,所以 File.xxx 函数不起作用。
# In the current working dir:
#
Dir.entries( '.' ).select{ |f| File.file? f }
# In another directory, relative or otherwise, you need to transform the path
# so it is either absolute, or relative to the current working dir to call File.xxx functions:
#
home = "/home/test"
Dir.entries( home ).select{ |f| File.file? File.join( home, f ) }
[1] .dotfile 在 unix 上,我不了解 Windows
【讨论】:
在 Ruby 2.5 中,您现在可以使用 Dir.children。它将文件名作为数组获取,“.”除外和“..”
例子:
Dir.children("testdir") #=> ["config.h", "main.rb"]
【讨论】:
就个人而言,我发现这对于循环遍历文件夹中的文件最有用,具有前瞻性:
Dir['/etc/path/*'].each do |file_name|
next if File.directory? file_name
end
【讨论】:
这是在目录中查找文件的解决方案:
files = Dir["/work/myfolder/**/*.txt"]
files.each do |file_name|
if !File.directory? file_name
puts file_name
File.open(file_name) do |file|
file.each_line do |line|
if line =~ /banco1/
puts "Found: #{line}"
end
end
end
end
end
【讨论】:
在获取目录中的所有文件名时,此 sn-p 可用于拒绝目录 [., ..] 和以 . 开头的隐藏文件
files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}
【讨论】:
Dir.entries 返回本地文件名,而不是绝对文件路径。另一方面,File.directory? 需要一个绝对文件路径。此代码未按预期工作。
此代码仅返回带有扩展名的文件名(没有全局路径)
Dir.children("/path/to/search/")
【讨论】:
这对我有用:
Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }
Dir.entries 返回一个字符串数组。然后,我们必须提供文件的完整路径到File.file?,除非dir 等于我们当前的工作目录。这就是为什么File.join()。
【讨论】:
您可能还想使用Rake::FileList(前提是您有rake 依赖项):
FileList.new('lib/*') do |file|
p file
end
根据 API:
文件列表是惰性的。当给出可能的 glob 模式列表时 要包含在文件列表中的文件,而不是搜索文件 结构来查找文件,FileList 保存后者的模式 使用。
【讨论】:
Dir.new('/home/user/foldername').each { |file| puts file }
【讨论】:
一种简单的方法可能是:
dir = './' # desired directory
files = Dir.glob(File.join(dir, '**', '*')).select{|file| File.file?(file)}
files.each do |f|
puts f
end
【讨论】:
如果您想获得文件名数组包括符号链接,请使用
Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }
甚至
Dir.new('/path/to/dir').reject { |f| File.directory? f }
如果您想不使用符号链接,请使用
Dir.new('/path/to/dir').select { |f| File.file? f }
如其他答案所示,如果要递归获取所有文件,请使用Dir.glob('/path/to/dir/**/*') 而不是Dir.new('/path/to/dir')。
【讨论】:
*.*
除了这个线程中的建议之外,我想提一下,如果您还需要返回点文件(.gitignore 等),那么使用 Dir.glob 您需要像这样包含一个标志:
Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH)
默认情况下,Dir.entries 包括点文件,以及当前的父目录。
对于任何感兴趣的人,我很好奇这里的答案在执行时间上是如何相互比较的,这里是针对深度嵌套层次结构的结果。前三个结果是非递归的:
user system total real
Dir[*]: (34900 files stepped over 100 iterations)
0.110729 0.139060 0.249789 ( 0.249961)
Dir.glob(*): (34900 files stepped over 100 iterations)
0.112104 0.142498 0.254602 ( 0.254902)
Dir.entries(): (35600 files stepped over 100 iterations)
0.142441 0.149306 0.291747 ( 0.291998)
Dir[**/*]: (2211600 files stepped over 100 iterations)
9.399860 15.802976 25.202836 ( 25.250166)
Dir.glob(**/*): (2211600 files stepped over 100 iterations)
9.335318 15.657782 24.993100 ( 25.006243)
Dir.entries() recursive walk: (2705500 files stepped over 100 iterations)
14.653018 18.602017 33.255035 ( 33.268056)
Dir.glob(**/*, File::FNM_DOTMATCH): (2705500 files stepped over 100 iterations)
12.178823 19.577409 31.756232 ( 31.767093)
这些是使用以下基准测试脚本生成的:
require 'benchmark'
base_dir = "/path/to/dir/"
n = 100
Benchmark.bm do |x|
x.report("Dir[*]:") do
i = 0
n.times do
i = i + Dir["#{base_dir}*"].select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.glob(*):") do
i = 0
n.times do
i = i + Dir.glob("#{base_dir}/*").select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.entries():") do
i = 0
n.times do
i = i + Dir.entries(base_dir).select {|f| !File.directory? File.join(base_dir, f)}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir[**/*]:") do
i = 0
n.times do
i = i + Dir["#{base_dir}**/*"].select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.glob(**/*):") do
i = 0
n.times do
i = i + Dir.glob("#{base_dir}**/*").select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.entries() recursive walk:") do
i = 0
n.times do
def walk_dir(dir, result)
Dir.entries(dir).each do |file|
next if file == ".." || file == "."
path = File.join(dir, file)
if Dir.exist?(path)
walk_dir(path, result)
else
result << file
end
end
end
result = Array.new
walk_dir(base_dir, result)
i = i + result.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
x.report("Dir.glob(**/*, File::FNM_DOTMATCH):") do
i = 0
n.times do
i = i + Dir.glob("#{base_dir}**/*", File::FNM_DOTMATCH).select {|f| !File.directory? f}.length
end
puts " (#{i} files stepped over #{n} iterations)"
end
end
文件计数的差异是由于Dir.entries 默认包含隐藏文件。 Dir.entries 在这种情况下最终花费了更长的时间,因为需要重建文件的绝对路径以确定文件是否为目录,但即使没有,它仍然比递归情况下的其他选项花费更长的时间.这都是在 OSX 上使用 ruby 2.5.1。
【讨论】:
加载操作目录下所有文件名时可以使用
Dir.glob("*)
这将返回应用程序运行的上下文中的所有文件(注意,Rails 这是应用程序的*目录)
您可以在 https://ruby-doc.org/core-2.7.1/Dir.html#method-c-glob 处找到额外的匹配和递归搜索
【讨论】:
def get_path_content(dir)
queue = Queue.new
result = []
queue << dir
until queue.empty?
current = queue.pop
Dir.entries(current).each { |file|
full_name = File.join(current, file)
if not (File.directory? full_name)
result << full_name
elsif file != '.' and file != '..'
queue << full_name
end
}
end
result
end
从目录和所有子目录返回文件的相对路径
【讨论】:
在 IRB 上下文中,您可以使用以下命令获取当前目录中的文件:
file_names = `ls`.split("\n")
您也可以在其他目录上进行此操作:
file_names = `ls ~/Documents`.split("\n")
【讨论】:
如果您创建带有空格的目录:
mkdir "a b"
touch "a b/c"
你不需要转义目录名,它会自动转义:
p Dir["a b/*"] # => ["a b/c"]
【讨论】: