Saya ingin mendapatkan semua nama file dari folder menggunakan Ruby.
Saya ingin mendapatkan semua nama file dari folder menggunakan Ruby.
Jawaban:
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"]
./...
daripada~/
./
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.
Dir.entries(folder)
contoh:
Dir.entries(".")
Sumber: http://ruby-doc.org/core/classes/Dir.html#method-c-entries
Dir#glob
mungkin 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" ...
Dir
jarang 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.
Dir[]
atau Dir.glob
ketika 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.
Cuplikan berikut persis menunjukkan nama file di dalam direktori, melewatkan subdirektori dan "."
, ".."
folder bertitik:
Dir.entries("your/folder").select {|f| !File.directory? f}
...select {|f| File.file? f}
untuk makna yang lebih jelas dan sintaks yang lebih pendek.
Dir.entries("your/folder").select {|f| File.file? f}
!File.directory?
sedang bekerja tetapi File.file?
tidak.
.reject {|f| File.directory? f}
tampaknya lebih bersih dari .select{|f| !File.directory? f}
. Oh, dan sekarang saya melihat komentar pertama ... juga bagus.
Untuk mendapatkan semua file (hanya file) secara rekursif:
Dir.glob('path/**/*').select{ |e| File.file? e }
Atau apa pun yang bukan direktori ( File.file?
akan menolak file tidak biasa):
Dir.glob('path/**/*').reject{ |e| File.directory? e }
Menggunakan Find#find
lebih dari metode pencarian berbasis pola seperti Dir.glob
sebenarnya lebih baik. Lihat jawaban ini untuk "Satu-liner ke Daftar Direktori secara Rekursif di Ruby?" .
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] .dotfile
di unix, saya tidak tahu tentang Windows
Di Ruby 2.5 sekarang Anda dapat menggunakan Dir.children
. Itu mendapatkan nama file sebagai array kecuali untuk "." dan ".."
Contoh:
Dir.children("testdir") #=> ["config.h", "main.rb"]
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
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
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.entries
mengembalikan nama file lokal, bukan path file absolut. Di sisi lain, File.directory?
mengharapkan jalur file absolut. Kode ini tidak berfungsi seperti yang diharapkan.
kode ini hanya mengembalikan nama file dengan ekstensi mereka (tanpa jalur global)
Dir.children("/path/to/search/")
Inilah yang bekerja untuk saya:
Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }
Dir.entries
mengembalikan array string. Kemudian, kita harus menyediakan path lengkap file File.file?
, kecuali dir
sama dengan direktori kerja kita saat ini. Itu sebabnya ini File.join()
.
Anda mungkin juga ingin menggunakan Rake::FileList
(asalkan Anda memiliki rake
ketergantungan):
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.
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.
*.*
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.entries
memasukkan file tersembunyi secara default. Dir.entries
akhirnya 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.
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
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
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")