วนซ้ำทุกไฟล์ในไดเรกทอรีเดียว


274

ฉันจะเขียนลูปเป็น ruby ​​เพื่อให้สามารถรันบล็อกโค้ดในแต่ละไฟล์ได้อย่างไร

ฉันใหม่กับทับทิมและฉันได้ข้อสรุปว่าวิธีการทำเช่นนี้คือทำทุกวง
ไฟล์ทับทิมจะถูกดำเนินการจากไดเรกทอรีอื่นที่ไม่ใช่ไดเรกทอรีที่ฉันต้องการวนซ้ำ

ฉันได้ลองDir.foreachแล้วก็ใช้งานไม่ได้


2
คุณสามารถระบุสิ่งที่เกิดขึ้นเมื่อคุณพยายามทำให้มันทำงานได้หรือไม่? คุณลองใช้รหัสอะไรจริง ๆ (หรืออันที่เกี่ยวข้องถ้ามันยาว) คุณได้รับข้อความแสดงข้อผิดพลาดอะไร Dir.foreachทำงานเพื่อย้ำเนื้อหาของไดเรกทอรีดังนั้นสิ่งอื่น ๆ ที่เกิดขึ้น
Telemachus

3
หากคุณต้องการเฉพาะไฟล์ภายในไดเรกทอรีของคุณอย่าลืมทดสอบไฟล์เมื่อวนซ้ำเนื้อหาในไดเรกทอรี: do_something_with(entry) if File.file?(entry)
glenn jackman

3
ใช้'img/*.{jpg,png,gif,jpeg}'เพื่อคว้าส่วนขยายหลายรายการ
Benjamin Crouzier

@ChrisPeters ดูเหมือนไม่น่าเสียดายเนื่องจาก OP ไม่ได้เข้ามาในเว็บไซต์ในรอบสี่ปี
Joe Kennedy

คำตอบ:


429

อย่างที่คนอื่น ๆ บอกไว้Dir::foreachเป็นตัวเลือกที่ดีที่นี่ อย่างไรก็ตามโปรดทราบว่าDir::foreachและDir::entriesจะรวม.และ..(ไดเรกทอรีปัจจุบันและไดเรกทอรีหลัก) เสมอ โดยทั่วไปคุณจะไม่ต้องการทำงานกับพวกเขาดังนั้นคุณสามารถใช้Dir::each_childหรือDir::children(ตามที่แนะนำโดย ma11hew28 ) หรือทำสิ่งนี้:

Dir.foreach('/path/to/dir') do |filename|
  next if filename == '.' or filename == '..'
  # Do work on the remaining files & directories
end

Dir::foreachและDir::entries(รวมถึงDir::each_childและDir::children) รวมถึงไฟล์และไดเรกทอรีที่ซ่อนอยู่ บ่อยครั้งที่สิ่งนี้เป็นสิ่งที่คุณต้องการ แต่ถ้าไม่ใช่คุณจำเป็นต้องทำบางสิ่งเพื่อข้ามมัน

หรือคุณอาจต้องการดูDir::globว่ามีการจับคู่ไวด์การ์ดแบบง่าย ๆ :

Dir.glob('/path/to/dir/*.rb') do |rb_filename|
  # Do work on files & directories ending in .rb
end

12
ใช้Dir.foreachหากไดเรกทอรีมีไฟล์จำนวนมาก!
Tilo

5
ขอบคุณ! ตัวnext if File.directory? item
ดัดแปลง

@ mr.buttons นั่นจะไม่ทำสิ่งที่ถูกต้องเสมอไป บางครั้งคนต้องการทำงานกับไดเรกทอรีเช่นเดียวกับไฟล์ ฉันให้รหัสเพื่อหลีกเลี่ยงรายการพิเศษสำหรับ.หรือ..เพราะคนมักจะไม่สนใจทั้งสอง
Telemachus

3
@Tilo: เพียงสนใจที่จะอธิบายในรายละเอียดอีกเล็กน้อยทำไม? :)
mkataja

11
@mkataja ทำDir.foreachซ้ำแทนการสร้างอาร์เรย์ (อาจใหญ่) ด้านหน้า (ซึ่งDir.globจะ) ดังนั้นหากไดเรกทอรีมีขนาดใหญ่มากมันสามารถสร้างความแตกต่างด้านประสิทธิภาพได้ ภายใต้สถานการณ์ปกติคุณจะไม่สังเกตเห็น แต่ภายใต้สภาวะความเครียดมันอาจมีความสำคัญอย่างยิ่ง
Telemachus

99

นี่เป็นวิธีที่ฉันชอบในการอ่านง่าย:

Dir.glob("*/*.txt") do |my_text_file|
  puts "working on: #{my_text_file}..."
end

และคุณสามารถขยายสิ่งนี้เพื่อทำงานกับไฟล์ทั้งหมดในส่วนย่อย:

Dir.glob("**/*.txt") do |my_text_file| # note one extra "*"
  puts "working on: #{my_text_file}..."
end

30

Dir ยังมีไวยากรณ์ที่สั้นกว่าเพื่อให้ได้อาร์เรย์ของไฟล์ทั้งหมดจากไดเรกทอรี:

Dir['dir/to/files/*'].each do |fname|
    # do something with fname
end

อะไรในรหัสนี้ป้องกันไดเรกทอรีจากการใช้fnameซ้ำกับ's?
kayleeFrye_onDeck


13

ไลบรารีการค้นหาถูกออกแบบมาสำหรับงานนี้โดยเฉพาะ: https://ruby-doc.org/stdlib-2.5.1/libdoc/find/rdoc/Find.html

require 'find'
Find.find(path) do |file|
  # process
end

นี่เป็นคลังทับทิมมาตรฐานดังนั้นควรใช้งานได้


1
File.findไปลงซ้ำเท่าที่จะทำได้เริ่มจากเส้นทางที่คุณให้ ฉันไม่แน่ใจว่าเป็นสิ่งที่ OP ต้องการ
Telemachus

ฉันดูเหมือนจะไม่สามารถเข้าถึงวิธีการนั้น - Find.find? ฉันจำเป็นต้องดาวน์โหลดไลบรารี ot ซึ่งรวมถึงฟังก์ชั่นนี้หรือไม่?
blue-sky

@ user470184: "Find" เป็นคลังทับทิมมาตรฐานและควรจะพร้อมใช้งานกับการติดตั้งทับทิมเริ่มต้น อย่างไรก็ตามคุณต้อง "ต้องการ" ค้นหา "" ก่อนจึงจะสามารถใช้งานได้
Faisal

1
@Faisal Can ฉันผ่านรูปแบบ glob เช่น*.rbไปfind()
Ashhar Hasan

7

ฉันชอบอันนี้ที่ไม่ได้กล่าวถึงข้างต้น

require 'pathname'

Pathname.new('/my/dir').children.each do |path|
    puts path
end

ประโยชน์คือการที่คุณได้รับวัตถุชื่อเส้นทางแทนสายอักขระที่คุณสามารถทำสิ่งที่มีประโยชน์ด้วยและสำรวจเพิ่มเติม


3
Dir.new('/my/dir').each do |name|
  ...
end

1
นอกจาก Dir.new ('/ my / dir') แล้วยังมี Dir.entries ('/ my / dir') แต่ Dir.foreach () นั้นค่อนข้างกระชับ
Tin Man

5
@ZED ยังDir.foreachวนซ้ำในขณะที่Dir.entriesสร้างอาร์เรย์ทั้งหมดขึ้นในครั้งเดียว ดังนั้นหากไดเรกทอรีมีขนาดใหญ่แสดงว่ามีจำนวนหน่วยความจำน้อยลง (ไม่ใช่เรื่องใหญ่มักจะ แต่ยัง ... )
Telemachus

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.