Dapatkan nama semua file dari folder dengan Ruby


Jawaban:


538

Anda juga memiliki opsi pintasan

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

dan jika Anda ingin menemukan semua file Ruby di folder atau sub-folder apa pun:

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

5
Atau Anda dapat melakukan hal yang sama dengan Dir :: glob ()
Yoann Le Touche

2
Juga, gunakan ./...daripada~/
Minh Triet

5
Mengapa ini lebih disukai?
BvuRVKyUVlViVIc7

1
@MinhTriet apa fungsinya? Apa yang lebih disukai?
stephenmurdoch

9
@marflar - ./berarti direktori saat ini, sedangkan /adalah titik mount root, dan ~/merupakan direktori home pengguna. Jika Anda memindahkan seluruh proyek ke tempat lain, yang pertama akan berhasil, tetapi dua lainnya mungkin tidak.
mirichan

170
Dir.entries(folder)

contoh:

Dir.entries(".")

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


15
Sepertinya dia menggunakan SO untuk mendokumentasikan jawaban atas pertanyaan yang baru saja dia tanyakan. Semacam memo, kurasa. Tidak dapat melihat banyak yang salah dengan itu - setelah semua, meskipun yang ini sedikit tidak lengkap ( Dir#globmungkin bisa disebutkan, misalnya) tidak ada yang mencegah orang lain dari memposting Jawaban yang Benar-Benar Baik. 'Tentu saja, saya sebagian besar jenis pria "gelas setengah penuh" ...
Mike Woodhouse

1
@ Mike: Dalam skema besar, mungkin bukan masalah besar. Dan seperti yang Anda katakan jika pertanyaan dan jawabannya bagus, itu bisa menjadi nilai tambah keseluruhan untuk situs tersebut. Tetapi di sini baik pertanyaan maupun jawaban sangat minim sehingga tampaknya tidak terlalu berguna.
Telemachus

17
@ Telemakus saya Dirjarang menggunakan , dan setiap kali saya membutuhkannya saya harus membaca dokumentasi. Saya telah memposting pertanyaan dan jawaban saya di sini sehingga saya dapat menemukannya nanti, dan mungkin bahkan membantu seseorang dengan pertanyaan yang sama. Saya pikir saya telah mendengar di SO podcast bahwa tidak ada yang salah dengan perilaku seperti itu. Jika Anda memiliki jawaban yang lebih baik, silakan kirim. Saya telah memposting apa yang saya ketahui, saya bukan seorang ninja Ruby. Saya secara teratur menerima jawaban dengan suara terbanyak.
Željko Filipin

Ini bisa menjadi pilihan yang lebih baik daripada Dir[]atau Dir.globketika argumen adalah variabel. Ketika path = '/tmp', membandingkan: Dir.glob("#{path}/*")vs Dir.entries(path). Nilai kembali sedikit berbeda (".", ".."), tetapi yang terakhir lebih mudah untuk dilihat sekilas.
Benjamin Oakes

92

Cuplikan berikut persis menunjukkan nama file di dalam direktori, melewatkan subdirektori dan ".", ".."folder bertitik:

Dir.entries("your/folder").select {|f| !File.directory? f}

19
Dapat juga dilakukan ...select {|f| File.file? f}untuk makna yang lebih jelas dan sintaks yang lebih pendek.
Otomatis

2
@ skixy Apakah Anda menuliskannya dengan benar ?:Dir.entries("your/folder").select {|f| File.file? f}
Automatico

9
Ya. !File.directory?sedang bekerja tetapi File.file?tidak.
Kamil Lelonek

2
@ squixy Saya memiliki masalah yang sama, dalam kasus saya, saya harus memberikan path lengkap bukan hanya nama file yang dikembalikan oleh Dir.foreach
TheLukeMcCarthy

6
.reject {|f| File.directory? f}tampaknya lebih bersih dari .select{|f| !File.directory? f}. Oh, dan sekarang saya melihat komentar pertama ... juga bagus.
Ian


18

Ini bekerja untuk saya:

Jika Anda tidak ingin file tersembunyi [1], gunakan 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 }

Sekarang, Dir.entries akan mengembalikan file tersembunyi, dan Anda tidak perlu wildcard asterix (Anda bisa meneruskan variabel dengan nama direktori), tetapi itu akan mengembalikan nama basenya langsung, sehingga fungsi File.xxx tidak akan berfungsi .

# 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] .dotfiledi unix, saya tidak tahu tentang Windows



9

Secara pribadi, saya menemukan ini yang paling berguna untuk pengulangan file dalam folder, melihat ke depan keamanan:

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

9

Ini adalah solusi untuk menemukan file di direktori:

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

6

Saat mendapatkan semua nama file dalam direktori, snippet ini dapat digunakan untuk menolak direktori [ ., ..] dan file tersembunyi yang dimulai dengan.

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

Dir.entriesmengembalikan nama file lokal, bukan path file absolut. Di sisi lain, File.directory?mengharapkan jalur file absolut. Kode ini tidak berfungsi seperti yang diharapkan.
Nathan

Sungguh aneh kodenya tidak berfungsi dalam kasus Anda. Karena ini adalah kode yang saya gunakan di aplikasi langsung yang berfungsi dengan baik. Saya akan memeriksa ulang kode saya dan memposting di sini jika ada sesuatu yang hilang dari kode kerja asli saya :)
Lahiru

1
@Nathan Lihat jawaban saya untuk penjelasan


4

Inilah yang bekerja untuk saya:

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

Dir.entriesmengembalikan array string. Kemudian, kita harus menyediakan path lengkap file File.file?, kecuali dirsama dengan direktori kerja kita saat ini. Itu sebabnya ini File.join().


1
Anda harus mengecualikan "." dan ".." dari entri
Edgar Ortega

3

Anda mungkin juga ingin menggunakan Rake::FileList(asalkan Anda memiliki rakeketergantungan):

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

Menurut API:

FileLists malas. Ketika diberi daftar pola glob untuk kemungkinan file yang akan dimasukkan dalam daftar file, alih-alih mencari struktur file untuk menemukan file, FileList memegang pola untuk penggunaan terakhir.

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


1

Jika Anda ingin mendapatkan array nama file termasuk symlink , gunakan

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

atau bahkan

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

dan jika Anda ingin pergi tanpa symlink , gunakan

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

Seperti yang ditunjukkan dalam jawaban lain, gunakan Dir.glob('/path/to/dir/**/*')alih-alih Dir.new('/path/to/dir')jika Anda ingin mendapatkan semua file secara rekursif.


Atau cukup gunakan*.*
Richard Peck

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

1

Selain saran di utas ini, saya ingin menyebutkan bahwa jika Anda perlu mengembalikan file dot juga (.gitignore, dll), dengan Dir.glob Anda harus menyertakan bendera sebagai berikut: Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) Secara default, Dir.entries termasuk file dot, serta direktori induk saat ini.

Bagi siapa pun yang tertarik, saya ingin tahu bagaimana jawaban di sini dibandingkan satu sama lain dalam waktu pelaksanaan, di sini adalah hasil terhadap hierarki yang sangat bersarang. Tiga hasil pertama adalah non-rekursif:

       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)

Ini dihasilkan dengan skrip pembandingan berikut:

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

Perbedaan dalam jumlah file adalah karena Dir.entriesmemasukkan file tersembunyi secara default. Dir.entriesakhirnya mengambil sedikit lebih lama dalam kasus ini karena perlu membangun kembali path absolut file untuk menentukan apakah file adalah direktori, tetapi bahkan tanpa itu masih secara konsisten memakan waktu lebih lama daripada opsi lain dalam kasus rekursif. Ini semua menggunakan ruby ​​2.5.1 di OSX.


1

Salah satu cara sederhana adalah:

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

files.each do |f|
    puts f
end

0
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

mengembalikan jalur relatif file dari direktori dan semua subdirektori


0

Dalam konteks IRB, Anda dapat menggunakan yang berikut ini untuk mendapatkan file di direktori saat ini:

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

Anda dapat membuat ini berfungsi di direktori lain juga:

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

Solusi ini bekerja untuk saya karena saya memiliki solusi lawas dengan versi ruby ​​lama yang tidak mendukung perintah Dir.children
Ciprian Dragoe
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.