class Tempfile

Eine Hilfsklasse zur Verwaltung temporärer Dateien.

Es gibt zwei Arten von Methoden zur Erstellung einer temporären Datei:

Tempfile.create erstellt ein normales File-Objekt. Der Zeitpunkt der Dateilöschung ist vorhersagbar. Außerdem unterstützt es die Open-and-Unlink-Technik, die die temporäre Datei sofort nach der Erstellung entfernt.

Tempfile.new und Tempfile.open erstellen ein Tempfile-Objekt. Die erstellte Datei wird vom GC (Finalizer) entfernt. Der Zeitpunkt der Dateilöschung ist nicht vorhersagbar.

Zusammenfassung

require 'tempfile'

# Tempfile.create with a block
# The filename are chosen automatically.
# (You can specify the prefix and suffix of the filename by an optional argument.)
Tempfile.create {|f|
  f.puts "foo"
  f.rewind
  f.read                # => "foo\n"
}                       # The file is removed at block exit.

# Tempfile.create without a block
# You need to unlink the file in non-block form.
f = Tempfile.create
f.puts "foo"
f.close
File.unlink(f.path)     # You need to unlink the file.

# Tempfile.create(anonymous: true) without a block
f = Tempfile.create(anonymous: true)
# The file is already removed because anonymous.
f.path                  # => "/tmp/"  (no filename since no file)
f.puts "foo"
f.rewind
f.read                  # => "foo\n"
f.close

# Tempfile.create(anonymous: true) with a block
Tempfile.create(anonymous: true) {|f|
  # The file is already removed because anonymous.
  f.path                # => "/tmp/"  (no filename since no file)
  f.puts "foo"
  f.rewind
  f.read                # => "foo\n"
}

# Not recommended: Tempfile.new without a block
file = Tempfile.new('foo')
file.path      # => A unique filename in the OS's temp directory,
               #    e.g.: "/tmp/foo.24722.0"
               #    This filename contains 'foo' in its basename.
file.write("hello world")
file.rewind
file.read      # => "hello world"
file.close
file.unlink    # deletes the temp file

Über Tempfile.new und Tempfile.open

Dieser Abschnitt gilt nicht für Tempfile.create, da er ein File-Objekt (nicht ein Tempfile-Objekt) zurückgibt.

Wenn Sie ein Tempfile-Objekt erstellen, wird eine temporäre Datei mit einem eindeutigen Dateinamen erstellt. Ein Tempfile-Objekt verhält sich genau wie ein File-Objekt, und Sie können alle üblichen Dateioperationen darauf ausführen: Daten lesen, Daten schreiben, Berechtigungen ändern usw. Obwohl diese Klasse nicht alle von File unterstützten Instanzmethoden explizit dokumentiert, können Sie tatsächlich jede File-Instanzmethode auf einem Tempfile-Objekt aufrufen.

Ein Tempfile-Objekt verfügt über einen Finalizer zur Entfernung der temporären Datei. Das bedeutet, dass die temporäre Datei über GC entfernt wird. Dies kann mehrere Probleme verursachen:

Es gibt bewährte Praktiken für Tempfile.new und Tempfile.open wie folgt:

Explizites Schließen

Wenn ein Tempfile-Objekt vom Garbage Collector übernommen wird oder wenn der Ruby-Interpreter beendet wird, wird die zugehörige temporäre Datei automatisch gelöscht. Das bedeutet, dass es nicht notwendig ist, ein Tempfile nach Gebrauch explizit zu löschen, obwohl es eine gute Praxis ist, dies zu tun: Das Nicht-explizite Löschen von ungenutzten Tempfiles kann potenziell eine große Anzahl von temporären Dateien auf dem Dateisystem hinterlassen, bis sie vom Garbage Collector übernommen werden. Die Existenz dieser temporären Dateien kann es schwieriger machen, einen neuen Tempfile-Dateinamen zu bestimmen.

Daher sollte man immer unlink oder close in einem ensure-Block aufrufen, wie hier:

file = Tempfile.new('foo')
begin
   # ...do something with file...
ensure
   file.close
   file.unlink   # deletes the temp file
end

Tempfile.create { ... } existiert zu diesem Zweck und ist bequemer zu verwenden. Beachten Sie, dass Tempfile.create eine File-Instanz anstelle eines Tempfile zurückgibt, was auch den Overhead und die Komplikationen der Delegation vermeidet.

Tempfile.create('foo') do |file|
   # ...do something with file...
end

Unlink nach Erstellung

Auf POSIX-Systemen ist es möglich, eine Datei zu unliken, unmittelbar nachdem sie erstellt und bevor sie geschlossen wurde. Dies entfernt den Dateisystemeintrag, ohne den Dateihandle zu schließen, und stellt somit sicher, dass nur die Prozesse, die bereits den Dateihandle geöffnet hatten, auf den Inhalt der Datei zugreifen können. Es wird dringend empfohlen, dies zu tun, wenn Sie nicht möchten, dass andere Prozesse von der Tempfile lesen oder darauf schreiben können und Sie den Dateinamen der Tempfile nicht kennen müssen.

Dies garantiert auch, dass die temporäre Datei entfernt wird, selbst wenn Ruby abnormal beendet wird. Das Betriebssystem gibt den Speicher für die temporäre Datei wieder frei, wenn die Datei geschlossen wird oder der Ruby-Prozess normal oder abnormal beendet wird.

Ein praktischer Anwendungsfall für Unlink-nach-Erstellung wäre zum Beispiel: Sie benötigen einen großen Bytepuffer, der zu groß ist, um bequem in den RAM zu passen, z. B. wenn Sie einen Webserver schreiben und die Upload-Daten des Clients zwischenspeichern möchten.

`Tempfile.create(anonymous: true)` unterstützt dieses Verhalten. Es funktioniert auch unter Windows.

Kleinere Hinweise

Die Methode zur Auswahl des Dateinamens von Tempfile ist sowohl Thread-sicher als auch Prozess-sicher: Sie garantiert, dass keine anderen Threads oder Prozesse denselben Dateinamen auswählen.

Tempfile selbst ist möglicherweise nicht vollständig Thread-sicher. Wenn Sie vom selben Tempfile-Objekt aus mehreren Threads zugreifen, sollten Sie es mit einem Mutex schützen.