简体   繁体   English

使用 Ruby 从文件夹中获取所有文件的名称

[英]Get names of all files from a folder with Ruby

我想使用 Ruby 从文件夹中获取所有文件名。

You also have the shortcut option of您还可以选择快捷方式

Dir["/path/to/search/*"]

and if you want to find all Ruby files in any folder or sub-folder:如果您想在任何文件夹或子文件夹中查找所有 Ruby 文件:

Dir["/path/to/search/**/*.rb"]
Dir.entries(folder)

example:例子:

Dir.entries(".")

Source: http://ruby-doc.org/core/classes/Dir.html#method-c-entries来源: http : //ruby-doc.org/core/classes/Dir.html#method-c-entries

The following snippets exactly shows the name of the files inside a directory, skipping subdirectories and "."以下片段准确显示了目录中文件的名称,跳过了子目录和"." , ".." dotted folders: , ".."虚线文件夹:

Dir.entries("your/folder").select { |f| File.file? File.join("your/folder", f) }

To get all files (strictly files only) recursively:递归获取所有文件(仅限文件):

Dir.glob('path/**/*').select { |e| File.file? e }

Or anything that's not a directory ( File.file? would reject non-regular files):或者任何不是目录的东西( File.file?会拒绝非常规文件):

Dir.glob('path/**/*').reject { |e| File.directory? e }

Alternative Solution替代方案

Using Find#find over a pattern-based lookup method like Dir.glob is actually better.在基于模式的查找方法(如Dir.glob )上使用Find#find实际上更好。 See this answer to "One-liner to Recursively List Directories in Ruby?"看到这个回答“One-liner to Recursively List Directories in Ruby?” . .

This works for me:这对我有用:

If you don't want hidden files[1], use Dir[] :如果您不想要隐藏文件[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 }

Now, Dir.entries will return hidden files, and you don't need the wildcard asterix (you can just pass the variable with the directory name), but it will return the basename directly, so the File.xxx functions won't work.现在, Dir.entries将返回隐藏文件,您不需要通配符星号(您可以只传递带有目录名的变量),但它会直接返回基名,因此 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 on unix, I don't know about Windows [1] unix 上的.dotfile ,我不知道 Windows

In Ruby 2.5 you can now use Dir.children .在 Ruby 2.5 中,您现在可以使用Dir.children It gets filenames as an array except for "."它以数组形式获取文件名,但“.”除外。 and ".."和“..”

Example:例子:

Dir.children("testdir")   #=> ["config.h", "main.rb"]

http://ruby-doc.org/core-2.5.0/Dir.html#method-c-children http://ruby-doc.org/core-2.5.0/Dir.html#method-c-children

Personally, I found this the most useful for looping over files in a folder, forward looking safety:就个人而言,我发现这对于循环文件夹中的文件最有用,前瞻性安全:

Dir['/etc/path/*'].each do |file_name|
  next if File.directory? file_name 
end

This is a solution to find files in a directory:这是在目录中查找文件的解决方案:

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

While getting all the file names in a directory, this snippet can be used to reject both directories [ .在获取目录中的所有文件名时,此代码段可用于拒绝两个目录 [ . , .. ] and hidden files which start with a . , .. ] 和以.开头的隐藏文件.

files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}

此代码仅返回带有扩展名的文件名(没有全局路径)

Dir.children("/path/to/search/")

This is what works for me:这对我有用:

Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }

Dir.entries returns an array of strings. Dir.entries返回一个字符串数组。 Then, we have to provide a full path of the file to File.file?那么,我们必须提供文件的完整路径到File.file? , unless dir is equal to our current working directory. , 除非dir等于我们当前的工作目录。 That's why this File.join() .这就是为什么这个File.join()

You may also want to use Rake::FileList (provided you have rake dependency):您可能还想使用Rake::FileList (前提是您有rake依赖项):

FileList.new('lib/*') do |file|
  p file
end

According to the API:根据API:

FileLists are lazy.文件列表是懒惰的。 When given a list of glob patterns for possible files to be included in the file list, instead of searching the file structures to find the files, a FileList holds the pattern for latter use.当给定要包含在文件列表中的可能文件的 glob 模式列表时,不是搜索文件结构来查找文件,而是 FileList 保存模式供以后使用。

https://docs.ruby-lang.org/en/2.1.0/Rake/FileList.html https://docs.ruby-lang.org/en/2.1.0/Rake/FileList.html

Dir.new('/home/user/foldername').each { |file| puts file }

If you want get an array of filenames including symlinks , use如果您想获得包含符号链接的文件名数组,请使用

Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }

or even甚至

Dir.new('/path/to/dir').reject { |f| File.directory? f }

and if you want to go without symlinks , use如果您想使用符号链接,请使用

Dir.new('/path/to/dir').select { |f| File.file? f }

As shown in other answers, use Dir.glob('/path/to/dir/**/*') instead of Dir.new('/path/to/dir') if you want to get all the files recursively.如其他答案所示,如果要递归获取所有文件,请使用Dir.glob('/path/to/dir/**/*')而不是Dir.new('/path/to/dir')

In addition to the suggestions in this thread, I wanted to mention that if you need to return dot files as well (.gitignore, etc), with Dir.glob you would need to include a flag as so: Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) By default, Dir.entries includes dot files, as well as current a parent directories.除了此线程中的建议之外,我还想提一下,如果您还需要返回点文件(.gitignore 等),则在 Dir.glob 中,您需要包含一个标志,如下所示: Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH)默认情况下,Dir.entries 包括点文件,以及当前的父目录。

For anyone interested, I was curious how the answers here compared to each other in execution time, here was the results against deeply nested hierarchy.对于任何感兴趣的人,我很好奇这里的答案在执行时间上如何相互比较,这是针对深层嵌套层次结构的结果。 The first three results are non-recursive:前三个结果是非递归的:

       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)

These were generated with the following benchmarking script:这些是使用以下基准测试脚本生成的:

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

The differences in file counts are due to Dir.entries including hidden files by default.文件计数的差异是由于Dir.entries默认包含隐藏文件。 Dir.entries ended up taking a bit longer in this case due to needing to rebuild the absolute path of the file to determine if a file was a directory, but even without that it was still taking consistently longer than the other options in the recursive case.在这种情况下,由于需要重建文件的绝对路径以确定文件是否是目录, Dir.entries最终花费了更长的时间,但即使没有它,它仍然比递归情况下的其他选项花费的时间更长. This was all using ruby 2.5.1 on OSX.这一切都是在 OSX 上使用 ruby​​ 2.5.1。

One simple way could be:一种简单的方法可能是:

dir = './' # desired directory
files = Dir.glob(File.join(dir, '**', '*')).select{|file| File.file?(file)}

files.each do |f|
    puts f
end

When loading all names of files in the operating directory you can use当加载操作目录中的所有文件名时,您可以使用

Dir.glob("*)

This will return all files within the context that the application is running in (Note for Rails this is the top level directory of the application)这将返回运行应用程序的上下文中的所有文件(注意对于 Rails,这是应用程序的顶级目录)

You can do additional matching and recursive searching found here https://ruby-doc.org/core-2.7.1/Dir.html#method-c-glob您可以在此处进行其他匹配和递归搜索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

returns file's relative paths from directory and all subdirectories从目录和所有子目录返回文件的相对路径

In an IRB context, you can use the following to get the files in the current directory:在 IRB 上下文中,您可以使用以下命令获取当前目录中的文件:

file_names = `ls`.split("\n")

You can make this work on other directories too:您也可以在其他目录上进行此操作:

file_names = `ls ~/Documents`.split("\n")

if you create directories with spaces:如果您创建带有空格的目录:

mkdir "a b"
touch "a b/c"

You don't need to escape the directory names, it will do it automatically:您不需要转义目录名称,它会自动执行:

p Dir["a b/*"] # => ["a b/c"]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM