ฉันต้องการรับชื่อไฟล์ทั้งหมดจากโฟลเดอร์โดยใช้ Ruby
ฉันต้องการรับชื่อไฟล์ทั้งหมดจากโฟลเดอร์โดยใช้ Ruby
คำตอบ:
คุณยังมีตัวเลือกทางลัดของ
Dir["/path/to/search/*"]
และหากคุณต้องการค้นหาไฟล์ทับทิมทั้งหมดในโฟลเดอร์หรือโฟลเดอร์ย่อย:
Dir["/path/to/search/**/*.rb"]
./...
มากกว่า~/
./
หมายถึงไดเรกทอรีปัจจุบันในขณะที่/
เป็นจุดเมาท์รูทและ~/
เป็นโฮมไดเรกทอรีของผู้ใช้ หากคุณย้ายโครงการทั้งหมดที่อื่นโครงการแรกจะใช้ได้ แต่อีกสองโครงการอาจไม่ทำงาน
Dir.entries(folder)
ตัวอย่าง:
Dir.entries(".")
ที่มา: http://ruby-doc.org/core/classes/Dir.html#method-c-entries
Dir#glob
อาจถูกกล่าวถึงเช่น) ไม่มีอะไรที่จะป้องกันไม่ให้คนอื่นโพสต์คำตอบที่ดีจริงๆ 'แน่นอนผมส่วนใหญ่เป็น 'ครึ่งแก้วเต็มรูปแบบ' การจัดเรียงของผู้ชาย ...
Dir
น้อยมากและทุกครั้งที่ฉันต้องการฉันก็ต้องอ่านเอกสาร ฉันโพสต์คำถามและคำตอบที่นี่เพื่อหาได้ในภายหลังและอาจช่วยคนที่มีคำถามเดียวกัน ฉันคิดว่าฉันเคยได้ยินที่พอดคาสต์ดังนั้นไม่มีอะไรผิดปกติกับพฤติกรรมดังกล่าว หากคุณมีคำตอบที่ดีกว่าโปรดโพสต์มัน ฉันโพสต์สิ่งที่ฉันรู้แล้วฉันไม่ใช่นินจาทับทิม ฉันยอมรับคำตอบอย่างสม่ำเสมอด้วยคะแนนโหวตมากที่สุด
Dir[]
หรือDir.glob
เมื่ออาร์กิวเมนต์เป็นตัวแปร เมื่อpath = '/tmp'
เปรียบเทียบ: VSDir.glob("#{path}/*")
Dir.entries(path)
ค่าส่งคืนจะแตกต่างกันเล็กน้อย (".", ".. "), แต่อย่างหลังนั้นง่ายกว่าที่จะติดตามอย่างรวดเร็ว
ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นว่าชื่อของไฟล์ภายในไดเรกทอรีไดเรกทอรีย่อยข้ามและ"."
, ".."
โฟลเดอร์ประ:
Dir.entries("your/folder").select {|f| !File.directory? 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
นั้นดีกว่าจริง ๆ ดูคำตอบนี้สำหรับ "ซับในหนึ่งรายการซ้ำในไดเรกทอรี 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
บนยูนิกซ์ฉันไม่รู้เกี่ยวกับ 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
ในขณะที่รับชื่อไฟล์ทั้งหมดในไดเรกทอรีตัวอย่างนี้สามารถใช้เพื่อปฏิเสธทั้งไดเรกทอรี [ .
, ..
] และไฟล์ที่ซ่อนซึ่งเริ่มต้นด้วย.
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:
FileLists ขี้เกียจ เมื่อได้รับรายการรูปแบบ glob สำหรับไฟล์ที่เป็นไปได้ที่จะรวมอยู่ในรายการไฟล์แทนที่จะค้นหาโครงสร้างไฟล์เพื่อค้นหาไฟล์ FileList จะเก็บรูปแบบไว้เพื่อใช้ในภายหลัง
หากคุณต้องการอาร์เรย์ของชื่อไฟล์รวมถึง symlinkให้ใช้
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')
หากคุณต้องการรับไฟล์ทั้งหมดซ้ำ
*.*
Dir.new('/home/user/foldername').each { |file| puts file }
นอกจากคำแนะนำในหัวข้อนี้ฉันต้องการพูดถึงว่าหากคุณต้องการส่งคืนไฟล์ dot เช่นกัน (.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
ลงเอยด้วยการใช้เวลานานขึ้นเล็กน้อยในกรณีนี้เนื่องจากจำเป็นต้องสร้างพา ธ สัมบูรณ์ของไฟล์อีกครั้งเพื่อพิจารณาว่าไฟล์เป็นไดเรกทอรีหรือไม่ แต่ถึงกระนั้นก็ยังใช้เวลานานกว่าตัวเลือกอื่น ๆ นี่คือทั้งหมดที่ใช้ทับทิม 2.5.1 บน OSX
วิธีง่ายๆวิธีหนึ่งอาจเป็น:
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
ส่งคืนพา ธ สัมพัทธ์ของไฟล์จากไดเรกทอรีและไดเรกทอรีย่อยทั้งหมด
ในบริบท IRB คุณสามารถใช้สิ่งต่อไปนี้เพื่อรับไฟล์ในไดเรกทอรีปัจจุบัน:
file_names = `ls`.split("\n")
คุณสามารถทำให้มันทำงานในไดเรกทอรีอื่น ๆ ได้เช่นกัน:
file_names = `ls ~/Documents`.split("\n")