Comment créer un fichier temporaire pouvant être lu par un sous-processus?

J’écris un script Python qui doit écrire des données dans un fichier temporaire, puis créer un sous-processus exécutant un programme C ++ qui lira le fichier temporaire. J’essaie d’utiliser NamedTemporaryFile pour cela, mais selon les documents,

Si le nom peut être utilisé pour ouvrir le fichier une seconde fois, alors que le fichier temporaire nommé est toujours ouvert, varie selon les plates-formes (il peut être utilisé sous Unix, mais pas sous Windows NT ou ultérieur).

En effet, sous Windows, si je vide le fichier temporaire après l’écriture, mais ne le ferme pas tant que je ne souhaite pas le supprimer, le sous-processus ne peut pas l’ouvrir pour le lire.

Je travaille sur ce sujet en créant le fichier avec delete=False , en le fermant avant de générer le sous-processus, puis en le supprimant manuellement une fois que j’ai terminé:

 fileTemp = tempfile.NamedTemporaryFile(delete = False) try: fileTemp.write(someStuff) fileTemp.close() # ...run the subprocess and wait for it to complete... finally: os.remove(fileTemp.name) 

Cela semble inélégant. Y a-t-il une meilleure manière de faire cela? Peut-être un moyen d’ouvrir les permissions sur le fichier temporaire afin que le sous-processus puisse y accéder?

Au moins, si vous ouvrez un fichier temporaire à l’aide de bibliothèques Python existantes, il est impossible d’y accéder à partir de plusieurs processus dans le cas de Windows. Selon MSDN, vous pouvez spécifier un indicateur de mode partagé 3ème paramètre ( dwSharedMode ) FILE_SHARE_READ à la fonction CreateFile() qui:

Permet les opérations ouvertes suivantes sur un fichier ou un périphérique pour demander un access en lecture. Sinon, d’autres processus ne peuvent pas ouvrir le fichier ou le périphérique s’ils demandent un access en lecture. Si cet indicateur n’est pas spécifié, mais que le fichier ou le périphérique a été ouvert pour un access en lecture, la fonction échoue.

Ainsi, vous pouvez écrire une routine C spécifique à Windows pour créer une fonction d’ouvre-fichier temporaire personnalisée, l’appeler à partir de Python et ensuite faire en sorte que votre sous-processus accède au fichier sans erreur. Mais je pense que vous devriez vous en tenir à votre approche existante car elle est la version la plus portable et fonctionnera sur tous les systèmes, ce qui en fait l’implémentation la plus élégante.

  • Vous trouverez des discussions sur Linux et le locking des fichiers Windows ici .

EDIT: il s’avère possible d’ouvrir et de lire le fichier temporaire de plusieurs processus dans Windows également. Voir la réponse de Piotr Dobrogost.

Puisque personne d’autre ne semble intéressé à laisser cette information à découvert …

tempfile expose une fonction, mkdtemp() , qui peut banaliser ce problème:

 try: temp_dir = mkdtemp() temp_file = make_a_file_in_a_dir(temp_dir) do_your_subprocess_stuff(temp_file) remove_your_temp_file(temp_file) finally: os.rmdir(temp_dir) 

Je laisse l’implémentation des fonctions intermédiaires au lecteur, comme on pourrait souhaiter utiliser des fonctions comme l’utilisation de mkstemp() pour renforcer la sécurité du fichier temporaire lui-même ou écraser le fichier sur place avant de le supprimer. Je ne sais pas particulièrement quelles ressortingctions de sécurité on pourrait avoir qui ne sont pas facilement planifiées en parcourant la source du tempfile .

Quoi qu’il en soit, oui, l’utilisation de NamedTemporaryFile sur Windows peut être inélégante, et ma solution ici peut aussi être inélégante, mais vous avez déjà décidé que le support Windows est plus important que le code élégant.

Selon Richard Oudkerk

(…) la seule raison pour laquelle essayer de rouvrir un NamedTemporaryFile échoue sous Windows est que lorsque nous O_TEMPORARY nous devons utiliser O_TEMPORARY .

et il donne un exemple de la façon de le faire dans Python 3.3+

 import os, tempfile DATA = b"hello bob" def temp_opener(name, flag, mode=0o777): return os.open(name, flag | os.O_TEMPORARY, mode) with tempfile.NamedTemporaryFile() as f: f.write(DATA) f.flush() with open(f.name, "rb", opener=temp_opener) as f: assert f.read() == DATA assert not os.path.exists(f.name) 

Comme il n’y a pas de paramètre d’ opener dans le os.open() os.fdopen() dans Python 2.x, nous devons combiner les fonctions os.open() et os.fdopen() niveau inférieur pour obtenir le même effet:

 import subprocess import tempfile DATA = b"hello bob" with tempfile.NamedTemporaryFile() as f: f.write(DATA) f.flush() subprocess_code = \ """import os f = os.fdopen(os.open(r'{FILENAME}', os.O_RDWR | os.O_BINARY | os.O_TEMPORARY), 'rb') assert f.read() == b'{DATA}' """.replace('\n', ';').format(FILENAME=f.name, DATA=DATA) subprocess.check_output(['python', '-c', subprocess_code]) == DATA 

Vous pouvez toujours aller à bas niveau, mais je ne suis pas sûr que ce soit assez propre pour vous:

 fd, filename = tempfile.mkstemp() try: os.write(fd, someStuff) os.close(fd) # ...run the subprocess and wait for it to complete... finally: os.remove(filename)