On veut traiter rapidement tous les octets d'un fichier et les enregistrer dans un autre fichier. Par exemple pour faire une inversion de bits, ou une rotation, etc…
Il faut d'abord une fonction de lecture-écriture de blocs de caractères. J'ai adapté pour cela ma fonction de copie de fichier:
def traitementfichier(nfcs, nfcd, lgbuf=16384): """Traitement des octets d'un fichier et écriture du résultat dans un autre fichier""" fs = None fd = None try: fs = open(nfcs, 'rb') fd = open(nfcd, 'wb') while True: buf = fs.read(lgbuf) if buf=="": break # .... # ici, traitement de buff qui est une chaine de lgbuf caractères # (ce traitement ne doit pas changer le nombre de caractères!!!) buf = traitementbuf(buf) # .... fd.write(buf) fs.close() fd.close() except: if fs != None: fs.close() if fd != None: fd.close() raise IOError # relance l'erreur pour la transmettre a l'appelant
Cette fonction lit des blocs 'buf' qui sont des chaines de caractères, appelle le traitement traitementbuf(buf). celui-ci transforme la chaine buf en liste d'octets, modifie les octets, et reconstitue à la fin la chaine (qui doit faire le même nombre de caractères). Cette chaine modifiée est écrite dans le fichier destination. Ceci jusqu'à la fin du fichier source (quand buf==“”).
On peut modifier à l'appel la taille du buffer (lgbuf=longueur de la chaine buf lue et écrite). Attention: le dernier buf lu n'a pas forcément la longueur lgbuf: ça dépend de la longueur totale du fichier!
Pour le traitement des octets, j'ai pris ici l'exemple d'une rotation d'un bit à droite, avec réinjection du bit de droite à gauche de l'octet:
rotd = lambda b: (b>>1) | ((b&1)<<7)
Par exemple,
b = 92 => 01011100 rotd(b) => 00101110 b = 93 => 01011101 rotd(b) => 10101110
Ce qui donne:
def traitementbuf(buf): bloc = [ord(c) for c in buf] # conversion de la chaine en liste d'octets # .... # ici, traitement des octets (= entiers de 0 à 255) de la liste bloc # par exemple: rotation à droite d'un bit de tous les octets bloc = [rotd(b) for b in bloc] # .... return ''.join([chr(b) for b in bloc]) # retour de la chaine modifiée
Et voilà comment on utilise ça (exemple ici sous Windows):
nfcs = r"C:\Users\Public\Documents\Wallpaper\FR-wp6.jpg" nfcd = r"C:\Users\Public\Documents\Wallpaper\FR-wp6_modif.jpg" try: traitementfichier(nfcs, nfcd) except IOError: print u"erreur de lecture/écriture"
J'ai essayé sur le fichier FR-wp6.jpg (du Windows 7) qui fait 775832 octets et le traitement est rapide (dans la seconde).
Amusez-vous bien!