2011-11-02 36 views
9

Tôi mới dùng Ruby (là một nhà phát triển Java) và cố gắng triển khai phương thức (oh, xin lỗi, một hàm) sẽ truy xuất và sinh ra tất cả các tệp trong thư mục con một cách đệ quy.danh sách tệp đệ quy trong Ruby

Tôi đã thực hiện nó như:

def file_list_recurse(dir) 
    Dir.foreach(dir) do |f| 
    next if f == '.' or f == '..' 
    f = dir + '/' + f 
    if File.directory? f 
     file_list_recurse(File.absolute_path f) { |x| yield x } 
    else 
     file = File.new(f) 
     yield file 
    end 
    end 
end 

Câu hỏi của tôi là:

  1. Liệu File.new thực sự mở một tập tin? Trong Java mới File ("xxx") không ... Nếu tôi cần phải mang lại một số cấu trúc mà tôi có thể truy vấn thông tin tập tin (ctime, kích thước vv) từ những gì nó sẽ được trong Ruby?
  2. {| x | năng suất x} trông hơi kỳ lạ đối với tôi, là OK để làm sản lượng từ các chức năng đệ quy như vậy, hoặc là có một số cách để tránh nó?
  3. Có cách nào để tránh kiểm tra '.' và '..' trên mỗi lần lặp?
  4. Có cách nào tốt hơn để thực hiện việc này không?

Cảm ơn

PS: việc sử dụng mẫu của phương pháp của tôi là một cái gì đó như thế này:

curr_file = nil 

file_list_recurse('.') do |file| 
    curr_file = file if curr_file == nil or curr_file.ctime > file.ctime 
end 

puts curr_file.to_path + ' ' + curr_file.ctime.to_s 

(mà sẽ giúp bạn có được các tập tin lâu đời nhất từ ​​cây)

= =========

Vì vậy, nhờ @buruza emon Tôi đã tìm ra hàm Dir.glob tuyệt vời đã lưu cho tôi một vài dòng mã. Ngoài ra, nhờ vào @Casper tôi phát hiện ra phương pháp File.stat, khiến chức năng của tôi chạy nhanh hơn với File.new

hai lần Cuối cùng mã của tôi đang tìm kiếm một cái gì đó như thế này:

i=0 
curr_file = nil 

Dir.glob('**/*', File::FNM_DOTMATCH) do |f| 
    file = File.stat(f) 
    next unless file.file? 
    i += 1 
    curr_file = [f, file] if curr_file == nil or curr_file[1].ctime > file.ctime 
end 

puts curr_file[0] + ' ' + curr_file[1].ctime.to_s 
puts "total files #{i}" 

=====

Theo mặc định Dir.glob bỏ qua tên tập tin bắt đầu với dấu chấm (coi là 'ẩn' trong * nix), vì vậy nó rất quan trọng để thêm file số thứ hai :: FNM_DOTMATCH

Trả lời

5

điều này nói với tôi để xem xét chấp nhận một câu trả lời, tôi hy vọng nó sẽ không nhớ tôi trả lời nó bản thân mình:

i=0 
curr_file = nil 

Dir.glob('**/*', File::FNM_DOTMATCH) do |f| 
    file = File.stat(f) 
    next unless file.file? 
    i += 1 
    curr_file = [f, file] if curr_file == nil or curr_file[1].ctime > file.ctime 
end 

puts curr_file[0] + ' ' + curr_file[1].ctime.to_s 
puts "total files #{i}" 
2

Bạn có thể sử dụng được xây dựng trong Find mô-đun của phương pháp find.

11

Làm thế nào về điều này?

puts Dir['**/*.*'] 
+0

Đó là tuyệt vời!Nhưng nó tạo ra một mảng các đối tượng String. Những gì tôi đang tìm kiếm là hàm sẽ tạo ra một cấu trúc giống như File để tôi có thể tự tính toán dựa trên đó. Tìm tập tin lớn nhất, ctime sớm nhất vv –

+0

Dir ['.'] Không chấp nhận một khối. Nhưng Dir.glob thì có! Nó trả lời các câu hỏi của tôi, ngoại trừ câu hỏi # 1 –

5

Theo tài liệu File.new sẽ mở tệp. Thay vào đó, bạn có thể muốn sử dụng File.stat, tập hợp các số liệu thống kê liên quan đến tệp vào một đối tượng có thể truy vấn. Nhưng lưu ý rằng các số liệu thống kê được tập hợp tại điểm sáng tạo. Không phải khi bạn gọi các phương thức truy vấn như ctime.

Ví dụ:

Dir['**/*'].select { |f| File.file?(f) }.map { |f| File.stat(f) } 
+1

File.stat trớ trêu thay không cung cấp tên của Tệp, vì vậy tôi không thể sử dụng nó làm đối tượng dữ liệu để trả về từ phương thức của tôi. Ngoài ra, tôi có một cây 200.000 tệp. Chạy kết quả ví dụ của bạn trong quá trình ruby ​​tăng trên 60 Mb, trong khi chạy phương thức của tôi (ngay cả với File.new) không bao giờ làm ruby ​​vượt quá 6 Mb. (Tôi đang thử nghiệm với đồng hồ -n 0,1 "ps ax -o comm, rss | grep ruby ​​>>/tmp/q"). Nhưng bạn dòng mẫu mã thực sự trông mát mẻ ;-) –

Các vấn đề liên quan