Generieren Sie temporäre Dateinamen, ohne eine tatsächliche Datei in Python zu erstellen

97

Die Frage mit der Nummer 10501247 im Stackoverflow gibt eine Antwort zum Erstellen einer temporären Datei in Python.
In meinem Fall muss ich nur einen temporären Dateinamen haben.
Wenn Sie tempfile.NamedTemporaryFile () aufrufen, wird das Dateihandle nach der eigentlichen Dateierstellung zurückgegeben.
Gibt es eine Möglichkeit, nur den Dateinamen abzurufen?

# Trying to get temp file path
tf = tempfile.NamedTemporaryFile()
temp_file_name = tf.name
tf.close()
# Here is my real purpose to get the temp_file_name
f = gzip.open(temp_file_name ,'wb')
...
Hügel
quelle
7
NamedTemporaryFilegarantiert einen eindeutigen Namen (wahrscheinlich), indem er versucht und erneut versucht wird, falls vorhanden. Wenn Sie nur einen Namen erhalten, können Sie nicht garantieren, dass Sie die Datei später tatsächlich erstellen können. Sie öffnen sich der Race-Bedingung einer anderen Person, die denselben Namen vor Ihnen verwendet.
Joachim Isaksson
5
@ Joachim Stimmt, hier gibt es eine Rennbedingung und es wäre vorzuziehen, dies zu vermeiden. Manchmal müssen Sie jedoch einen temporären Dateinamen an eine Funktion übergeben (Datei wird intern geöffnet). Ein schön zufälliger Name bietet eine viel bessere Wahrscheinlichkeit, dass die Rennbedingung kein Problem darstellt. Ich denke, es besteht ein gültiger Bedarf, einen guten temporären Dateinamen anzugeben, um die Wahrscheinlichkeit eines Versagens der Rennbedingungen zu minimieren. Das Hinzufügen eines guten Präfixes und Suffixes basierend auf dem laufenden Prozess und der ausgeführten Aufgabe bietet natürlich noch weniger Chancen auf eine Kollision.
PolyMesh
@PolyMesh Sie können die Race-Bedingung vermeiden, indem Sie ein temporäres Verzeichnis erstellen und dann eine feste Namensdatei darin verwenden. Ihre Funktion akzeptiert also ein Verzeichnis anstelle einer Datei und erstellt immer dieselbe Datei.
DylanYoung
benutze tarfile und gib es dem fileobj
Wyrmwood

Antworten:

67

Wenn Sie nur einen temporären Dateinamen möchten, können Sie die innere temporäre Funktion aufrufen _get_candidate_names():

import tempfile

temp_name = next(tempfile._get_candidate_names())
% e.g. px9cp65s

Wenn Sie nexterneut anrufen , wird ein anderer Name usw. zurückgegeben. Dies gibt Ihnen nicht den Pfad zum temporären Ordner. Verwenden Sie zum Abrufen des Standardverzeichnisses 'tmp':

defult_tmp_dir = tempfile._get_default_tempdir()
% results in: /tmp 
Marcin
quelle
3
Der bessere Weg temp_dir = tempfile.mkdtemp(prefix='some-prefix_'), ein temporäres Verzeichnis zu erstellen, besteht darin, ein temporäres Verzeichnis sicher zu erstellen und eine Zeichenfolge mit dem absoluten Pfad zurückzugeben.
Emanuel Ey
3
Es ist wichtig darauf hinzuweisen, dass next(tempfile._get_candidate_names())nicht unbedingt ein nicht vorhandener Pfad zurückgegeben wird. Aus diesem Grund können Tempfile-Schnittstellen auf Benutzerebene mehrere Namen ausprobieren, bis ein nicht verwendeter gefunden wird :
Eli Korvigo
1
Man könnte öffentlich tempfile.gettempdir()statt privat verwenden tempfile._get_default_tempdir().
Flonk
@EmanuelEy Es ist wichtig zu beachten, dass tempfile.mkdtempder Benutzer für die Löschung des temporären Verzeichnisses und seines Inhalts verantwortlich ist, wenn er damit fertig ist.
Daniel Braun
45

Ich denke, der einfachste und sicherste Weg, dies zu tun, ist etwa:

path = os.path.join(tempfile.mkdtemp(), 'something')

Es wird ein temporäres Verzeichnis erstellt, auf das nur Sie zugreifen können. Es sollten also keine Sicherheitsprobleme auftreten, es werden jedoch keine Dateien erstellt. Sie können also einfach einen beliebigen Dateinamen auswählen, den Sie in diesem Verzeichnis erstellen möchten.

Bearbeiten: In Python 3 können Sie jetzt tempfile.TemporaryDirectory()als Kontextmanager das Löschen für Sie übernehmen:

with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, 'something')
  # use path
Alec
quelle
1
Wie Daniel Braun oben erwähnt hat: Es ist wichtig, sich daran zu erinnern, dass tempfile.mkdtempder Benutzer für die Löschung des temporären Verzeichnisses und seines Inhalts verantwortlich ist, wenn er damit fertig ist.
Bitinerant
4
Wenn Sie tempfile.TemporaryDirectory()als Kontextmanager verwenden, wird dieser für Sie gelöscht.
Gerrit
17

Es mag etwas spät sein, aber stimmt etwas nicht?

import tempfile
with tempfile.NamedTemporaryFile(dir='/tmp', delete=False) as tmpfile:
    temp_file_name = tmpfile.name
f = gzip.open(temp_file_name ,'wb')
Russell
quelle
36
Dieser Code erstellt tatsächlich die temporäre Datei, um ihren Namen zu erhalten, während in der Frage angegeben without creating actual file in Python.
Jakub Kukul
Dies beantwortet die Frage nicht
Herve
8

tempfile.mktemp() mach das.

Beachten Sie jedoch, dass es veraltet ist. Die Datei wird jedoch nicht erstellt, und es handelt sich um eine öffentliche Funktion in tempfile im Vergleich zur Verwendung von_get_candidate_names() .

Der Grund, warum es veraltet ist, liegt in der Zeitspanne zwischen dem Aufruf und dem tatsächlichen Versuch, die Datei zu erstellen. In meinem Fall ist die Chance dafür jedoch so gering, und selbst wenn dies fehlschlagen würde, wäre dies akzeptabel. Aber es liegt an Ihnen, für Ihren Anwendungsfall zu bewerten.

Zitrax
quelle
1
"Selbst wenn es scheitern würde, wäre das akzeptabel"; Die Rennbedingung ist nicht nur ein Ausfallrisiko, sondern auch ein Sicherheitsrisiko (siehe tempfile.mktempDokumentation). Das sollte also nicht als akzeptabel angesehen werden.
Bignose
4
@bignose Es ist ein potenzielles Sicherheitsproblem. Es hängt davon ab, was Sie tun möchten, in welcher Ausführungsumgebung Sie sich befinden usw. Das heißt: Es ist möglicherweise sicherer, so etwas zu tun. os.path.join(tempfile.mkdtemp(), 'something')Dort wird zumindest das Verzeichnis erstellt (und gehört Ihnen, nehme ich an).
Alec
5

Meine Lösung kombiniert die vorherigen Antworten und lautet:

def get_tempfile_name(some_id):
    return os.path.join(tempfile.gettempdir(), next(tempfile._get_candidate_names()) + "_" + some_id)

Machen Sie some_idoptional, wenn nicht für Sie benötigt.

Juanmirocks
quelle
Auch hier sind die Kandidatennamen möglicherweise nicht verfügbar. Dies ist die richtige Antwort: stackoverflow.com/a/45803022/6387880
j4hangir
1
Wahrscheinlich muss man jedoch zufällige Namen erstellen. Wenn dies _get_candidate_names()jedoch nicht vorhanden ist, kann standardmäßig ein halbzufälliger Zeichenfolgengenerator verwendet werden. Zum Beispiel eine UUID.
Juanmirocks
4

Wie Joachim Isaksson in den Kommentaren sagte, können Sie Probleme haben, wenn Sie nur einen Namen erhalten, wenn ein anderes Programm diesen Namen verwendet, bevor Ihr Programm dies tut. Die Chancen sind gering, aber nicht unmöglich.

In dieser Situation ist es daher sicher, den vollständigen GzipFile () -Konstruktor zu verwenden, der über die Signatur verfügt GzipFile( [filename[, mode[, compresslevel[, fileobj]]]]). Sie können also die geöffnete Dateiobjj und, wenn Sie möchten, auch einen Dateinamen übergeben. Weitere Informationen finden Sie in den gzip-Dokumenten.

PM 2Ring
quelle