Ruby ile bir klasördeki tüm dosyaların adlarını alma


Yanıtlar:


538

Ayrıca kısayol seçeneğiniz de var

Dir["/path/to/search/*"]

ve tüm Ruby dosyalarını herhangi bir klasör veya alt klasörde bulmak istiyorsanız:

Dir["/path/to/search/**/*.rb"]

5
Veya aynısını Dir :: glob ()
Yoann Le Touche ile de yapabilirsiniz

2
Ayrıca, ./...yerine kullanın~/
Minh Triet

5
Bu neden tercih edilir?
BvuRVKyUVlViVIc7

1
@ MinhTriet bu ne işe yarar? Tercih edilen nedir?
stephenmurdoch

9
@marflar - ./geçerli dizin anlamına gelir, oysa /kök bağlama noktası ve ~/kullanıcının ana dizini. Tüm projeyi başka bir yere taşırsanız, birincisi işe yarar, ancak diğer ikisi muhtemelen işe yaramaz.
mirichan

170
Dir.entries(folder)

misal:

Dir.entries(".")

Kaynak: http://ruby-doc.org/core/classes/Dir.html#method-c-entries


15
Sorduğu soruların cevaplarını belgelemek için SO kullanıyor. Sanırım bir tür not. Bu konuda pek yanlış göremiyorum - sonuçta, bu biraz eksik olsa da ( Dir#globörneğin, belki de bahsedilebilirdi), başka birinin Gerçekten İyi Bir Yanıt göndermesini engelleyecek hiçbir şey yok. 'course, ben çoğunlukla "cam yarı dolu" bir adamım ...
Mike Woodhouse

1
@Mike: Şeylerin büyük planında, muhtemelen büyük bir sorun değil. Söylediğiniz gibi, soruların ve cevapların iyi olup olmadığını, site için bir artı olabilir. Ancak burada hem soru hem de cevap o kadar azdır ki, özellikle yararlı görünmemektedir.
Telemachus

17
@Telemachus DirNadiren kullanıyorum ve her ihtiyaç duyduğumda belgeleri okumak zorundayım. Sorumu daha sonra bulabilmem için buraya gönderdim ve yanıtladım ve hatta aynı soruyu bilen birine yardım edebilirim. Sanırım SO podcast'de böyle bir davranışta yanlış bir şey olmadığını duydum. Daha iyi bir cevabınız varsa, lütfen gönderin. Bildiklerimi yayınladım, Ruby Ruby değilim. En çok oyu alan cevapları düzenli olarak kabul ediyorum.
jeljko Filipin

Bu , bağımsız değişken bir değişken olduğunda Dir[]veya Dir.globbu değişkenten daha iyi bir seçenek olabilir . Ne zaman path = '/tmp', karşılaştırma: Dir.glob("#{path}/*")vs Dir.entries(path). Dönüş değerleri biraz farklıdır (".", ".."), ancak ikincisine hızlı bir bakışla bakılması daha kolaydır.
Benjamin Oakes

92

Aşağıdaki parçacıkları tam bir dizin içindeki dosya, atlama alt dizinleri ve adını gösterir ".", ".."noktalı klasörler:

Dir.entries("your/folder").select {|f| !File.directory? f}

19
...select {|f| File.file? f}Daha net anlam ve daha kısa sözdizimi için de yapabilir .
Automatico

2
@squixy Doğru yazdınız mı ?:Dir.entries("your/folder").select {|f| File.file? f}
Automatico

9
Evet. !File.directory?çalışıyor ama File.file?çalışmıyor.
Kamil Lelonek

2
@squixy Aynı sorunu yaşadım, benim durumumda sadece Dir.foreach tarafından döndürülen dosya adını değil tam yolu sağlamalıyım
TheLukeMcCarthy

6
.reject {|f| File.directory? f}daha temiz görünüyor .select{|f| !File.directory? f}. Oh, ve şimdi ilk yorumu görüyorum ... ayrıca iyi.
Ian

36

Tüm dosyaları (yalnızca dosyalar) yinelemeli olarak almak için:

Dir.glob('path/**/*').select{ |e| File.file? e }

Veya dizin File.file?olmayan herhangi bir şey ( normal olmayan dosyaları reddeder):

Dir.glob('path/**/*').reject{ |e| File.directory? e }

Alternatif çözüm

Kullanımı Find#findgibi bir desen tabanlı arama yöntemi üzerinde Dir.globaslında iyidir. Bkz için bu cevabı "Ruby yinelemeli Liste Dizinler Tek astar?" .


18

Bu benim için çalışıyor:

Gizli dosya istemiyorsanız [1], Dir [] kullanın :

# 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 }

Şimdi, Dir.entries gizli dosyaları döndürür ve joker karakter asterixine ihtiyacınız yoktur (değişkeni dizin adıyla geçirebilirsiniz), ancak doğrudan temel adı döndürür, böylece File.xxx işlevleri çalışmaz .

# 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] .dotfileunix'te Windows hakkında bir fikrim yok



9

Şahsen, bunu bir klasördeki dosyalar üzerinde ileriye dönük güvenlik için en kullanışlı buldum:

Dir['/etc/path/*'].each do |file_name|
  next if File.directory? file_name 
end

9

Bu, bir dizindeki dosyaları bulmak için bir çözümdür:

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

6

Bir dizindeki tüm dosya adlarını alırken, bu pasajı, hem dizinleri [reddetmek için kullanılabilir ., ..a ile başlar] ve gizli dosyaları.

files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}

Dir.entriesmutlak dosya yollarını değil, yerel dosya adlarını döndürür. Öte yandan, File.directory?mutlak bir dosya yolu bekler. Bu kod beklendiği gibi çalışmıyor.
Nathan

Kod sizin durumunuzda çalışmıyor garip. Bu iyi çalışıyor canlı bir uygulamada kullandığınız bir kod olduğu için. Orijinal çalışma
kodumda

1
@Nathan Bir açıklama için cevabımı gör


4

İşte benim işime yarayan bu:

Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }

Dir.entriesbir dizgi dizisi döndürür. Ardından, geçerli çalışma dizinimize eşit File.file?olmadığı sürece dosyanın tam yolunu sağlamalıyız dir. Bu yüzden bu File.join().


1
"" İfadesini hariç tutmanız gerekir. ve girişlerden ".."
Edgar Ortega

3

Ayrıca kullanmak isteyebilirsiniz Rake::FileList( rakebağımlılığınız varsa):

FileList.new('lib/*') do |file|
  p file
end

API'ya göre:

Dosya Listeleri tembeldir. Dosyaları bulmak için dosya yapılarını aramak yerine, dosya listesine dahil edilecek olası dosyalar için bir glob kalıpları listesi verildiğinde, bir FileList, ikinci kullanım için kalıbı tutar.

https://docs.ruby-lang.org/en/2.1.0/Rake/FileList.html


1

Simge bağlantıları da dahil olmak üzere bir dizi dosya adı almak istiyorsanız şunu kullanın:

Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }

ya da

Dir.new('/path/to/dir').reject { |f| File.directory? f }

ve sembolik bağlar olmadan gitmek istiyorsanız ,

Dir.new('/path/to/dir').select { |f| File.file? f }

Diğer yanıtlarda gösterildiği gibi, tüm dosyaları yinelemeli olarak almak istiyorsanız Dir.glob('/path/to/dir/**/*')yerine kullanın Dir.new('/path/to/dir').


Veya sadece kullanın*.*
Richard Peck

1
Dir.new('/home/user/foldername').each { |file| puts file }

1

Bu konudaki önerilere ek olarak, nokta dosyalarını da (.gitignore vb.) Döndürmeniz gerekiyorsa, Dir.glob ile bir bayrak eklemeniz gerektiğini belirtmek Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) istedim : Varsayılan olarak, Dir.entries nokta dosyaları ve geçerli bir üst dizinleri içerir.

İlgilenen herkes için, burada cevapların yürütme zamanında nasıl karşılaştırıldığını merak ettim, işte derin iç içe hiyerarşiye karşı sonuçlar oldu. İlk üç sonuç özyinelemesizdir:

       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)

Bunlar aşağıdaki karşılaştırma komut dosyasıyla oluşturuldu:

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

Dosya sayımlarındaki farklar, Dir.entriesvarsayılan olarak gizli dosyaların dahil edilmesinden kaynaklanmaktadır . Dir.entriesbir dosyanın bir dizin olup olmadığını belirlemek için dosyanın mutlak yolunu yeniden oluşturmaya ihtiyaç duyması nedeniyle bu durumda biraz daha uzun sürdü, ancak bu olmadan bile özyinelemeli durumda diğer seçeneklerden sürekli olarak daha uzun sürüyordu. Bunların hepsi OSX'te ruby ​​2.5.1 kullanıyordu.


1

Basit bir yol olabilir:

dir = './' # desired directory
files = Dir.glob(File.join(dir, '**', '*')).select{|file| File.file?(file)}

files.each do |f|
    puts f
end

0
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

dizinden ve tüm alt dizinlerden dosyanın göreli yollarını döndürür


0

IRB bağlamında, geçerli dizindeki dosyaları almak için aşağıdakileri kullanabilirsiniz:

file_names = `ls`.split("\n")

Bu işlemi diğer dizinlerde de yapabilirsiniz:

file_names = `ls ~/Documents`.split("\n")

Dir.children komutunu desteklemeyen eski yakut sürümüne sahip eski bir çözümüm olduğu için bu çözümler benim için çalıştı
Ciprian Dragoe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.