2010-03-24 16 views
250

Jak napisać pętlę w Ruby, aby móc wykonać blok kodu na każdym pliku?Powtórz każdy plik w jednym katalogu

Jestem nowy w Ruby i doszedłem do wniosku, że sposobem na zrobienie tego jest wykonanie każdej pętli.
Plik ruby ​​zostanie wykonany z innego katalogu niż katalog, który chcę przeliczyć.

Próbowałem już Dir.foreach i nie mogłem go uruchomić.

+2

Czy możesz określić, co się stało, gdy próbowałeś to zrobić? Jaki dokładnie kod próbowałeś (lub odpowiedni fragment, jeśli jest długi)? Jakie komunikaty o błędach dostałeś? 'Dir.foreach' działa w celu iteracji zawartości katalogu, więc dzieje się coś innego. – Telemachus

+3

Jeśli chcesz tylko pliki w twoim katalogu, nie zapomnij przetestować plików podczas iteracji nad zawartością katalogu: 'do_something_with (entry) if File.file? (Entry)' –

+3

Użyj ''img/*. {Jpg, png, gif, jpeg} ", aby pobrać wiele rozszerzeń. –

Odpowiedz

22
Dir.foreach("/home/mydir") do |fname| 
    puts fname 
end 
+1

Można również użyć Dir # [] lub Dir # glob –

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

Oprócz Dir.new ('/ my/dir') istnieją również Dir.entries ('/ my/dir'), ale Dir.foreach() jest nieco bardziej zwięzły. –

+4

@ Z.E.D. Również 'Dir.foreach' iteruje, podczas gdy' Dir.entries' buduje całą tablicę naraz. Więc jeśli katalog jest olbrzymi, to mniejszy hit pamięci. (Zazwyczaj nie jest to wielka sprawa, ale nadal ...) – Telemachus

391

Jak mówili inni, Dir.foreach jest dobrym rozwiązaniem tutaj. Należy jednak pamiętać, że Dir.entries i Dir.foreach zawsze będą wyświetlać . i .. (katalogi bieżące i macierzyste). Generalnie nie chcą pracować na nich, więc można zrobić coś takiego:

Dir.foreach('/path/to/dir') do |item| 
    next if item == '.' or item == '..' 
    # do work on real items 
end 

Dir.foreach i Dir.entries pokazują również wszystkie pozycje w katalogu - ukryte i nie ukryte podobni. Często tego właśnie chcesz, ale jeśli nie, musisz zrobić coś, aby pominąć ukryte pliki i katalogi.

Alternatywnie, można zajrzeć do Dir.glob który zapewnia proste dopasowanie wieloznaczny:

Dir.glob('/path/to/dir/*.rb') do |rb_file| 
    # do work on files ending in .rb in the desired directory 
end 
+11

Użyj 'Dir.foreach', jeśli katalog zawiera ogromną liczbę plików! – Tilo

+4

dzięki! Mały modyfikator, aby był jeszcze lepszy: 'next if File.directory? item' –

+0

@ mr.buttons Nie zawsze będzie to właściwe. Czasami ludzie chcą pracować nad * katalogami *, a także plikami. Podałem kod, aby unikać specjalnych wpisów dla '.' lub' ..', ponieważ ludzie prawie zawsze chcą zignorować tych dwóch. – Telemachus

11

Biblioteka znalezisko jest zaprojektowany do tego celu w szczególności: http://stdlib.rubyonrails.org/libdoc/find/rdoc/index.html

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

Jest to standardowy rubin biblioteka, więc powinna być dostępna:

+1

'File.find' idzie rekurencyjnie w dół tak daleko, jak to możliwe, zaczynając od dowolnej ścieżki, którą mu podasz. Nie jestem pewien, czy tego chce OP. – Telemachus

+0

Nie wydaje mi się, że mam dostęp do tej metody - Find.find? Czy muszę pobrać bibliotekę ot zawiera tę funkcję? –

+0

@ user470184: "Znajdź" jest standardową biblioteką ruby ​​i powinno być dostępne z domyślną instalacją ruby. Musisz jednak "wymagać" znalezienia "" zanim będziesz mógł z niego skorzystać. – Faisal

91

To jest moja ulubiona metoda na łatwe w brzmieniu:

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

I można nawet rozszerzyć to do pracy na wszystkich plikach w subdirs:

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

Dir ma również krótszy składni, aby uzyskać tablicę wszystkich plików z katalogu:

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

Co w tym kodzie zapobiega używaniu katalogów również w iteracjach' fname'? –

2

Podoba mi się ten, o którym nie wspomniano powyżej.

require 'pathname' 

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

Zaletą jest to, że zamiast obiektu tekstowego otrzymuje się obiekt Pathname, dzięki któremu można robić użyteczne rzeczy i przechodzić dalej.

Powiązane problemy