IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

pack_into et buffer modifiable


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut pack_into et buffer modifiable
    Bonjour,

    j'ai un petit code tout gentil qui veut écrire des données binaires dans un fichier.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> import struct
    >>> output = struct.pack( 'II',1,2 )
    >>> output += struct.pack( 'II',3,4 )
    >>> output
    '\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
    Jusque là tout va bien.

    Le seul truc un peu compliqué c'est que je veut modifier un peu mon output avant de l'écrire : je veux remplacer le 3 par 444.
    Naïvement je fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    >>> struct.pack_into('I',output,struct.calcsize('II'),444 )
    mais là, erreur, "Cannot use string as modifiable buffer" !

    J'ai commencé à chercher, mais je ne trouve que des solutions à base de array. Et dans ce cas, pas moyen d'utiliser struct.pack...

    De manière un peu plus générique, je veux :

    - construire une string (ou n'importe quoi d'équivalant) par des concaténations successives avec struct.pack.
    - modifier (de temps en temps) ma string déjà construite avec struct.pack_into.
    - écrire le tout dans un fichier.
    ---> et bien sûr je ne connais pas la taille totale avant la fin...

    Je ne peux pas croire qu'il n'existe pas un moyen simple et élégant de faire ça en python !

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Par défaut
    Tu es en Python 3 , non ?

    Sous Python 2.7 , print output me sort des carrés.

    Pour afficher la valeur de output, je suis obligé d’utiliser repr(output)






    Puisque
    7.3 struct - Interpret strings as packed binary data

    This module performs conversions between Python values and C structs represented as Python strings.
    j’ai fait ça pour répondre à ton problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import struct
    output = struct.pack( 'II',1,2 )
    output += struct.pack( 'II',3,4 )
    print repr(output)
     
    def repl_in(out,x,y):
        I = struct.pack( 'I',x )
        i = out.find(I)
        return out[:i] + struct.pack( 'I',y ) + out[i+len(I):]
     
    output = repl_in(output,3,444)
    print repr(output)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    '\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
    '\x01\x00\x00\x00\x02\x00\x00\x00\xbc\x01\x00\x00\x04\x00\x00\x00'



    Mais au vu de ce que tu veux faire:
    - construire une string (ou n'importe quoi d'équivalant) par des concaténations successives avec struct.pack.
    - modifier (de temps en temps) ma string déjà construite
    - écrire le tout dans un fichier.
    je me demande si tu n’aurais pas intérêt à regarder du coté du module IO.

    Il y a une classe class io.BufferedIOBase dont les instances sont des « binary streams that support some kind of buffering » qui peuvent être modifiées par des write()

  3. #3
    Membre Expert
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Par défaut
    Tu peux créer un "string buffer" à l'aide de la fonction make_string_buffer du module ctypes. Cela ne répond pas entièrement à tes besoins car il faut préciser la taille à la création, mais je doute que tu trouves exactement ce que tu cherches.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> from ctypes import create_string_buffer
    >>> b = create_string_buffer(8)
    >>> b
    <ctypes.c_char_Array_8 object at 0x02561210>
    >>> ''.join(x for x in b)
    '\x00\x00\x00\x00\x00\x00\x00\x00'
    >>> import struct
    >>> struct.pack_into('I',b,4,444)
    >>> ''.join(x for x in b)
    '\x00\x00\x00\x00\xbc\x01\x00\x00'
    Bien sûr dans ce cas tu ne dois plus utiliser que struct.pack_into et plus du tout struct.pack.

    [EDIT] Bon finalement, tu peux même utiliser le module array avec struct.pack_into:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> a = array.array('I',[1,2,3,4])
    >>> a
    array('I', [1L, 2L, 3L, 4L])
    >>> struct.pack_into('I',a,8,444)
    >>> a
    array('I', [1L, 2L, 444L, 4L])
    # on peut même faire des trucs bizarres comme:
    >>> struct.pack_into('f',a,2,3.4)
    >>> a
    array('I', [2577006593L, 16473L, 444L, 4L])

  4. #4
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Je plussoie dividee pour l'emploi de array pour l'écriture en binaire.
    http://docs.python.org/library/array.html
    Tes problèmes peuvent être résolus avec les méthodes pop et insert voir doc ci-dessus.
    utilisation basique:
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/usr/bin/env python
    import array
    data = array.array('B') 
    data.append(ord('A'))
    data.append(ord('1'))
    data.append(int('11111111', 2)) # 255, 0xFF
    print data
    f = file('data.bin', 'wb')
    data.tofile(f)
    f.close()
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 068
    Par défaut
    j'utiliserai plutôt bytearray ... qui est built-in.
    c'est mutable et ça se manipule comme un str et une liste combinés.
    Suffit de taper dir(bytearray) pour se rendre compte de la puissance du truc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    output = bytearray('ma_chaine')
    output += bytearray('_plus_longue')
    str(output)     # ==> 'ma_chaine_plus_longue'
    output = output.replace('plus','encore_plus')
    str(output)     #==>'ma_chaine_encore_plus_longue'
    output[17:21]='+'
    str(output)    #==>'ma_chaine_encore_+_longue'
    output.insert(18,43)
    str(output)    #==> 'ma_chaine_encore_++_longue'
    pour initialiser une liste de 10 octets ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    bytearray(10) # ==> bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
    Bref, on ne peut plus s'en passer ...
    Le hic c'est que ça ne manipule que des octets

    Citation Envoyé par sopsag Voir le message
    Je ne peux pas croire qu'il n'existe pas un moyen simple et élégant de faire ça en python !
    y a un truc sympas en python qui permet de faire tout ce qu'on veut ... c'est le fait de pouvoir créer ses propres class. Quand tu ne trouves pas l'outil que tu veux, tu le fabriques

  6. #6
    Membre confirmé Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Par défaut
    Citation Envoyé par josmiley Voir le message
    y a un truc sympas en python qui permet de faire tout ce qu'on veut ... c'est le fait de pouvoir créer ses propres class. Quand tu ne trouves pas l'outil que tu veux, tu le fabriques
    Bien sûr !
    C'est ce que je suis en train de faire...
    J'écris le what-millième serialisateur de ma longue carrière de développeur !
    Jusque là, je les écrivais en C ou en C++, mais je pensais le besoin tellement classique et récurrent que python m'en fournirait un déjà tout mâché dans une lib...
    D'autant que la lib struct est vraiment très bien pensée.
    Mais le fait qu'il faille choisir entre un append dynamique et accès aléatoire statique est vraiment dommage. D'autant plus que ce n'est qu'une limitation de l'API. Je pense qu'il n'y aurait aucune difficulté à ajouter la possibilité d'éditer ce qui a déjà été sérialisé.
    C'est comme si les développeurs de cette lib n'avaient jamais pensé que ce besoin pourrait se présenter...
    Pourtant le coup du "je sérialise des données puis je reviens au début pour indiquer leur taille" est très classique.

    En tous cas, tu m'as convaincu d'utiliser les bytearray dans mon serialisateur... même si j'aimais bien la façon très élégante de gérer l'endiannesse de struct.

Discussions similaires

  1. Réponses: 3
    Dernier message: 20/10/2013, 15h55
  2. Modifier l'échelle d'une image dans un buffer
    Par alainb dans le forum Débuter
    Réponses: 9
    Dernier message: 17/08/2011, 20h11
  3. Réponses: 2
    Dernier message: 03/01/2007, 18h17
  4. Modifier un vertex buffer? (débutant)
    Par Myrhev dans le forum DirectX
    Réponses: 5
    Dernier message: 12/07/2006, 14h03
  5. Alpha blending et Z-buffer directx 8
    Par Cesar4 dans le forum DirectX
    Réponses: 1
    Dernier message: 23/05/2002, 12h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo