Comment envelopper un descripteur de fichier existant en tant qu’objet fichier Python

Vous avez un descripteur de fichier entier correspondant à un canal d’E/S déjà ouvert sur le système d’exploitation (par exemple, fichier, pipe, socket, etc.), et vous voulez l’entourer par un objet fichier Python de niveau supérieur. Donc, cet article vous convient.

Un descripteur de fichier est différent d’un fichier ouvert normal en ce sens qu’il s’agit simplement d’une valeur entière attribuée par le système d’exploitation pour se référer à une sorte de canal E/S du système.

Si vous avez un tel descripteur de fichier, vous pouvez l’entourer d’un objet de fichier Python en utilisant la fonction open().

Cependant, vous fournissez simplement le descripteur de fichier entier comme premier argument au lieu du nom de fichier. Par exemple:

# Ouvrir un descripteur de fichier de bas niveau
import os
fd = os.open('fichier.txt', os.O_WRONLY | os.O_CREAT)

#  Transformez-le en un fichier approprié
f = open(fd, 'wt')
f.write('hello world\n')
f.close()

Lorsque l’objet de fichier de haut niveau est fermé ou détruit, le descripteur de fichier sous-jacent sera également fermé. Si ce n’est pas désiré, fournissez l’argument optionnel closefd=False à la fonction open(). Par exemple:

# Créez un objet fichier, mais ne fermez pas le fd sous-jacent une fois terminé
f = open(fd, 'wt', closefd=False)
...

Sur les systèmes Unix, cette technique d’habillage d’un descripteur de fichier peut être un moyen pratique de placer une interface de type fichier sur un canal d’E/S existant qui a été ouvert d’une manière différente (par exemple, tubes, sockets, etc.).

Par exemple, voici un exemple concernant les sockets:

from socket import socket, AF_INET, SOCK_STREAM

def echo_client(client_sock, addr):
    print('Connexion à partir de ', addr)

    # Faire des enveloppes de fichiers en mode texte pour la lecture/écriture de sockets
    client_in = open(client_sock.fileno(), 'rt', encoding='latin-1',
                         closefd=False)
    client_out = open(client_sock.fileno(), 'wt', encoding='latin-1',
                          closefd=False)

    # Lignes d'écho renvoyées au client à l'aide de l'E/S de fichier
    for ligne in client_in:
        client_out.write(ligne)
        client_out.flush()
    client_sock.close()

def echo_server(address):
    sock = socket(AF_INET, SOCK_STREAM)
    sock.bind(address)
    sock.listen(1)
    while True:
        client, addr = sock.accept()
        echo_client(client, addr)

 

Il est important de souligner que l’exemple ci-dessus est uniquement destiné à illustrer une fonctionnalité de la fonction intégrée open() et qu’il ne fonctionne que sur les systèmes basés sur Unix.

Si vous essayez de mettre une interface de type fichier sur un socket et que votre code doit être multi plate-forme, utilisez la méthode makefile() des sockets à la place.

Cependant, si la portabilité n’est pas un problème, vous constaterez que la solution ci-dessus fournit de bien meilleures performances que l’utilisation de makefile().

Vous pouvez également utiliser ceci pour créer une sorte d’alias qui permet d’utiliser un fichier déjà ouvert d’une manière légèrement différente de la façon dont il a été ouvert au départ.

Par exemple, voici comment vous pouvez créer un objet fichier qui vous permet d’émettre des données binaires sur stdout (qui est normalement ouvert en mode texte):

import sys
# Créer un fichier en mode binaire pour stdout
bstdout = open(sys.stdout.fileno(), 'wb', closefd=False)
bstdout.write(b'Hello World\n')
bstdout.flush()

Bien qu’il soit possible d’envelopper un descripteur de fichier existant comme un fichier normal, sachez que tous les modes de fichiers ne sont pas supportés et que certains types de descripteurs de fichiers peuvent avoir des effets secondaires (notamment en ce qui concerne la gestion des erreurs, les conditions de fin de fichier, etc…).

Le comportement peut également varier selon le système d’exploitation. En particulier, aucun de ces exemples n’est susceptible de fonctionner sur des systèmes non-Unix.

En fin de compte, vous devrez tester à fond votre implémentation pour vous assurer qu’elle fonctionne comme prévu.

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here