Mappage mémoire des fichiers binaires

Vous voulez mapper en mémoire un fichier binaire dans un tableau d’octets mutable, éventuellement pour un accès aléatoire à son contenu ou pour faire des modifications sur place.

Utilisez le module mmap pour créer des fichiers map mémoire. Voici une fonction utilitaire qui montre comment ouvrir un fichier et le mapper en mémoire de manière portable:

import os
import mmap

def memory_map(filename, access=mmap.ACCESS_WRITE):
   taille = os.path.getsize(fichier)
   df = os.open(fichier, os.O_RDWR)
   return mmap.mmap(df, taille, access=access)

 

Pour utiliser cette fonction, vous devez avoir un fichier déjà créé et rempli de données. Voici un exemple de la façon dont vous pourriez initialement créer un fichier et l’étendre à la taille désirée :

>>> taille = 1000000
>>> with open('donnees', 'wb') as f:
... f.seek(taille-1)
... f.write(b'\x00')
...
>>>

 

Voici maintenant un exemple de mappage mémoire du contenu à l’aide de la fonction memory_map():

>>> m = memory_map('donnees')
>>> len(m)
1000000
>>> m[0:10]
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> m[0]
0

>>> # Réaffecter une tranche
>>> m[0:11] = b'Hello World'
>>> m.close()

>>> # Vérifier que des changements ont été apportés
>>> with open('donnees', 'rb') as f:
... print(f.read(11))
...
b'Hello World'
>>>

 

L’objet mmap retourné par mmap() peut également être utilisé comme gestionnaire de contexte, auquel cas le fichier sous-jacent est fermé automatiquement. Par exemple:

>>> with memory_map('donnees') as m:
... print(len(m))
... print(m[0:10])
...
1000000
b'Hello World'
>>> m.closed
True
>>>

 

Par défaut, la fonction memory_map() montrée ouvre un fichier à la fois en lecture et en écriture. Toute modification apportée aux données est copiée dans le fichier d’origine.

Si l’accès en lecture seule est nécessaire à la place, fournissez la valeur mmap.ACCESS_READ à l’argument access. Pour exemple:

m = memory_map(fichier, mmap.ACCESS_READ)

 

Si vous avez l’intention de modifier les données localement, mais que vous ne voulez pas que ces modifications soient écrites dans le fichier original, utilisez mmap.ACCESS:

m = memory_map(fichier, mmap.ACCESS_COPY)

 

L’utilisation de mmap pour mapper des fichiers en mémoire peut être un moyen efficace et élégant d’accéder de manière aléatoire au contenu d’un fichier.

Par exemple, au lieu d’ouvrir un fichier et d’effectuer diverses combinaisons d’appels seek(), read() et write(), vous pouvez simplement mapper le fichier et accéder aux données en utilisant des opérations de découpage (slicing en anglais).

Normalement, la mémoire visible par mmap() ressemble à un objet bytearray. Toutefois, vous pouvez interpréter les données différemment à l’aide d’une vue mémoire. Par exemple:

>>> m = memory_map('donnees')
>>> # Vue mémoire d'entiers non signés
>>> v = memoryview(m).cast('I')
>>> v[0] = 7
>>> m[0:4]
b'\x07\x00\x00\x00'
>>> m[0:4] = b'\x07\x01\x00\x00'
>>> v[0]
263
>>>

 

Il convient de souligner que le mappage mémoire d’un fichier n’entraîne pas la lecture en mémoire de l’intégralité du fichier. C’est-à-dire qu’il n’est pas copié dans une sorte de mémoire tampon ou de tableau. Au lieu de cela, le système d’exploitation réserve simplement une section de mémoire virtuelle pour le contenu du fichier.

Lorsque vous accédez à différentes régions, ces parties du fichier seront lues et mappées dans la région mémoire selon les besoins. Cependant, les parties du fichier qui ne sont jamais accessibles restent simplement sur le disque. Tout cela se passe de manière transparente, en coulisses.

Si plus d’un interpréteur Python mappe le même fichier, l’objet mmap résultant peut être utilisé pour échanger des données entre les interpréteurs.

En d’autres termes, tous les interprètes peuvent lire/écrire des données simultanément, et les modifications apportées aux données d’un interprète apparaissent automatiquement dans les autres.

Évidemment, une attention particulière est nécessaire pour synchroniser les choses, mais ce type d’approche est parfois utilisé comme alternative à la transmission de données dans les messages sur des tubes ou sockets.

Comme montré, cet exemple a été écrit pour être aussi générale que possible, fonctionnant sous Unix et Windows. Sachez qu’il y a quelques différences de plate-forme concernant l’utilisation de l’appel mmap() caché dans les coulisses.

De plus, il existe des options pour créer des régions de mémoire anonymement mappées. Si cela vous intéresse, assurez-vous de lire attentivement la documentation Python à ce sujet.

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here