Dateien in Ruby filtern: ein praktischer Leitfaden
Effizientes Filtern von Dateien ist überall unverzichtbar, von der Log-Verarbeitung bis zur Medienverwaltung. Ruby bietet robuste Werkzeuge für die Dateiauswahl, die über einfachen Musterabgleich hinausgehen. Sehen wir uns praxisnahe Techniken an, die von einfachen bis zu fortgeschrittenen Szenarien skalieren.
Voraussetzungen
Dieser Leitfaden setzt für Dir.children Ruby 2.5 oder neuer voraus. Die gezeigten Beispiele verwenden
Ruby 3.2.3 und mime-types 3.6.0. Für die Erkennung von MIME-Typen benötigen Sie das mime-types-Gem:
# Add to your Gemfile
gem 'mime-types', '3.6.0'
Oder installieren Sie dieselbe Version direkt:
gem install mime-types -v 3.6.0
Das mime-types-Gem verwendet eine angepasste semantische Versionierung, um sowohl API-Änderungen als auch Aktualisierungen der Registry-Daten abzubilden. Weitere Details finden Sie in der mime-types-Dokumentation.
Zentrale Filtermethoden
Rubys Standardbibliothek bietet mehrere sofort einsetzbare Lösungen zum Filtern von Dateien:
# Filter by extension
docs_dir = '/docs'
pdf_files = Dir.children(docs_dir).select do |f|
File.file?(File.join(docs_dir, f)) && File.extname(f) == '.pdf'
end
# Filter by size (1MB threshold)
large_files = Dir.glob('*').select do |f|
begin
File.file?(f) && File.size(f) > 1_000_000
rescue Errno::ENOENT, Errno::EACCES => e
warn "Error accessing #{f}: #{e.message}"
false
end
end
# Filter by modification time (last 24 hours)
recent_files = Dir.glob('*').select do |f|
begin
File.file?(f) && File.mtime(f) > (Time.now - 86400)
rescue Errno::ENOENT, Errno::EACCES => e
warn "Error accessing #{f}: #{e.message}"
false
end
end
Diese Methoden nutzen die Hilfsfunktionen der Klasse File für schnelle Prüfungen, ohne Dateiinhalte zu laden.
Fortgeschrittener Musterabgleich mit glob
Rubys Dir.glob unterstützt Musterabgleich im UNIX-Stil mit einigen Ruby-spezifischen Erweiterungen:
# Match nested Markdown files
markdown_files = Dir.glob('**/*.md').select { |f| File.file?(f) }
# Match names containing a January 2024 date (not modification times)
jan_files = Dir.glob('*').grep(/(2024-01-\d{2})/).select { |f| File.file?(f) }
# Combined size and type filter
big_images = Dir.glob('*.{jpg,png}').select do |f|
begin
File.file?(f) && File.size(f) > 500_000
rescue Errno::ENOENT, Errno::EACCES => e
warn "Error accessing #{f}: #{e.message}"
false
end
end
Verwenden Sie den doppelten Stern (**) für das rekursive Durchlaufen von Verzeichnissen und die
Klammererweiterung für mehrere Dateiendungen.
MIME-Typen nachschlagen
Verwenden Sie das Gem mime-types, um den Medientyp nachzuschlagen, der zu einer Dateiendung gehört:
require 'mime/types'
def media_files(dir)
Dir.children(dir).select do |f|
begin
next unless File.file?(File.join(dir, f))
mime = MIME::Types.type_for(f).first
mime&.media_type == 'image' || mime&.media_type == 'video'
rescue StandardError => e
warn "Error processing #{f}: #{e.message}"
false
end
end
end
# Usage:
visual_assets = media_files('/content/assets')
Dieser Ansatz nutzt eine Registry von Dateiendungen; er prüft weder Dateiinhalte noch stellt er sicher, dass eine Datei unbedenklich ist. Setzen Sie eine Inhaltsprüfung separat ein, wenn Sie Uploads aus nicht vertrauenswürdigen Quellen annehmen. Weitere Details finden Sie in der Dokumentation zum mime-types-Gem.
Filtern nach Metadaten
Kombinieren Sie mehrere Metadaten-Angaben für eine präzise Auswahl:
def recent_documents(path)
Dir.glob("#{path}/*").select do |f|
begin
next unless File.file?(f)
ext = File.extname(f).downcase
size = File.size(f)
modified = File.mtime(f)
(ext == '.pdf' || ext == '.docx') &&
size.between?(10_000, 5_000_000) &&
modified > (Time.now - 7*86400)
rescue StandardError => e
warn "Error processing #{f}: #{e.message}"
false
end
end
end
Damit werden PDF-/DOCX-Dateien ausgewählt, die in der letzten Woche geändert wurden und zwischen 10 KB und 5 MB groß sind.
Performance-Überlegungen
Beim Verarbeiten großer Verzeichnisse:
-
Verzögerte Auswertung: Verschieben Sie Metadaten-Prüfungen mit
lazy.Dir.globerstellt sein Ergebnis-Array dennoch.Dir.glob('**/*').lazy .select { |f| File.file?(f) && File.size(f) > 1_000_000 } .first(10) -
Früher Abbruch: Steigen Sie nach Möglichkeit frühzeitig mit
breakauslog_dir = '/logs' Dir.children(log_dir).each do |name| f = File.join(log_dir, name) begin next unless File.file?(f) && f.end_with?('.log') break if File.size(f) > 1_000_000_000 # Stop at first huge log process_log(f) rescue StandardError => e warn "Error processing #{f}: #{e.message}" end endDefinieren Sie
process_log(path)für die Verarbeitung in Ihrer Anwendung, bevor Sie diesen Ausschnitt ausführen. -
Metadaten-Caching: Speichern Sie häufig abgerufene Daten
file_cache = {} Dir.glob('*').each do |f| begin file_cache[f] = { mtime: File.mtime(f), size: File.size(f) } rescue StandardError => e warn "Error caching #{f}: #{e.message}" end end
Produktionsreifes Beispiel
Hier ist ein vollständiges Filtermodul mit Fehlerbehandlung:
require 'mime/types'
class FileFilter
def initialize(root_dir)
@root = root_dir
end
def find_files(extensions: [], min_size: 0, max_age: Float::INFINITY)
Dir.glob(File.join(@root, '**', '*')).lazy.select do |path|
begin
next unless File.file?(path)
valid_extension = extensions.empty? || extensions.include?(File.extname(path))
valid_size = File.size(path) >= min_size
valid_age = (Time.now - File.mtime(path)) < max_age
valid_extension && valid_size && valid_age
rescue StandardError => e
warn "Error processing #{path}: #{e.message}"
false
end
end
end
end
# Usage:
filter = FileFilter.new('/user/uploads')
recent_images = filter.find_files(
extensions: ['.jpg', '.png'],
min_size: 100_000,
max_age: 3600 # 1 hour
).first(100)
Diese Beispiele zeigen praxisnahe Wege, um Dateien in Ruby mit robuster Fehlerbehandlung zu filtern. Für fortgeschrittenere Lösungen zur Dateiverarbeitung lohnt sich ein Blick auf die API von Transloadit. Weitere Details finden Sie in unserer Dokumentation.
Umgang mit Zeichenkodierungen von Dateien
Ruby verarbeitet die Zeichenkodierung von Dateinamen in der Regel automatisch, wenn UTF-8 verwendet wird. Falls es jedoch zu Problemen mit Nicht-ASCII-Zeichen in Dateinamen kommt, erzeugen Sie einen UTF-8-Anzeigewert wie folgt:
# Convert from Ruby's known source encoding and replace invalid bytes for display
utf8_labels = Dir.glob('*').map do |f|
f.encode('UTF-8', invalid: :replace, undef: :replace).scrub
end
Behalten Sie den ursprünglichen Pfad für Dateisystem-Operationen bei. Ersatzzeichen können einen
Dateinamen verändern; diese Bezeichnungen dienen ausschließlich der Anzeige. force_encoding kennzeichnet Bytes lediglich neu und transkodiert sie nicht.
Fazit
In diesem Leitfaden haben wir praxisnahe Techniken zum Filtern von Dateien in Ruby betrachtet, von einfachen Prüfungen der Dateiendung über Glob-Muster bis hin zur Erkennung von MIME-Typen und dem Filtern nach Metadaten. Durch die Kombination dieser Methoden können Sie effiziente Pipelines zur Dateiverarbeitung aufbauen, die auf Ihre Anforderungen zugeschnitten sind. Für umfangreiche, produktionsreife Lösungen lohnt sich ein Blick auf die robuste API zur Dateiverarbeitung von Transloadit. Mehr erfahren Sie in unserer Dokumentation.
