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 :

lire et écrire dans un fichier en mode r+


Sujet :

Python

  1. #1
    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 lire et écrire dans un fichier en mode r+
    lire écrire lecture écriture fichier texte txt mode r+ seek tell write writelines
    update actualiser corriger actualisation correction
    réécrire modifier modification



    J'en ai eu marre de ne rien comprendre à la façon dont fonctionnent les modes de fichier r+ w+ a+ , et je me suis donc attelé à chercher des explications sur le net.

    Ce n'était pas la première fois et j'ai de nouveau eu l'impression d'être comme Théodore Monod à la recherche de la météorite de Chinguetti: on ne trouve quasiment rien !
    C'est le désert d'explications sur ce sujet pourtant très essentiel. Les explications qu'on trouve sont pour la plupart sommaires et toujours les mêmes.
    Il se peut qu'il y ait des explications en bonne et due forme sur developpez.com, mais même si c'est le cas, le fait est que je ne les ai pas trouvées.
    De même, dans le livre de Swinnen qui est tellement porté aux nues, une recherche de 'r+' conduit à UNE seule occurence de ces caractères dans tout le livre, et encore est-ce seulement au sein du code d'un exemple. Aucun chapitre spécifique ne détaille ce sujet dans ce livre, sauf erreur.
    Dans "Plonger au cœur de Python" il n'y a rien non plus.
    En recherchant dans les divers forums sur Internet je me suis souvent perdu dans la masse de références plus ou moins bien liées à ma question, et je n'ai en tous cas pas trouvé de réponses expliquant les choses avec clarté qui m'aient permis de comprendre le sujet.
    Déprimant et énervant.
    Mais cette fois ci, je me suis obstiné.




    On lit ici ou là que
    l'ouverture en modes 'r' et 'r+' positionne le pointeur au début du fichier,
    tandis que l'ouverture en modes 'a' et 'a+' le positionne à la fin.

    Je me suis fixé de d'abord comprendre comment marche ce foutu mode 'r+'. Est-ce qu'on ne peut écrire qu'au début du fichier ? Peut on écrire au milieu ?

    Je suis retombé sur la page suivante,
    http://jam-bazaar.blogspot.com/2007/...-r-w-mode.html
    Je le connaissais déjà mais je n'en avais pas tiré profit parce que l'extrait suivant est ambigü:

    « However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired. »

    À cause du "or" et du "if desired" , on a l'impression que lorsqu'on veut passer de lecture à écriture, il suffit d'une seule des fonctions fflush, fsetpos, fseek, or rewind.
    En plus ce sont des fonctions de C++, et le texte met ça en relation avec une erreur que commet Windows et que je n'ai jamais observée personnellement.
    En outre, il ne précise pas ce qu'on peut lire dans la Python Library Reference à propos de fsync() dont je me suis oportunément souvenu (ça sert de se balader parfois dans le manuels):

    « If you're starting with a Python file object f, first do f.flush(), and then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk. »




    Il m'est soudain apparu qu'il était évident qu'il FAUT utiliser flush() pour écrire dans un fichier en mode 'r+' et que si ça n'avait pas marché quand j'avais fait des essais, même avec flush(), c'est parce que j'essayais d'écrire trop peu de caractères sans avoir utilisé fsync().

    J'ai de nouveaux fait des essais avec flush() et fsync() mais ça marchait de façon erratique. Jusqu'à ce qu'à force de tatonnements, j'arrive à une compréhension qui est synthétisée dans le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    from os import fsync
     
    def execution(x,comm):
        print '---------------------------------------------------------------\n'+x+')'+comm
        # Creation de fichierY
        f = open('fichierY','w')
        f.write('France: Paris\nAllemagne: Berlin\nAutriche: Vienne\n')
        f.close()
        # Tentative d'ecriture en mode r+
        f = open('fichierY','r+')
        if x=='1':  pass
        if x=='2':  f.readline()
        if x=='3':
            p = f.tell()
        if x=='4':
            f.readline()
            p = f.tell()
        if x=='5':
            f.seek(18)
        if x=='6':
            f.readline()
            f.seek(18)
        f.write(ch)
        f.flush()
        fsync(f.fileno())
        f.close()
        # Visualisation du resultat
        f = open('fichierY','r')
        while 1:
            p,rd = f.tell(),f.readline()
            if not rd:  break
            print 'p =',str(p+1000)[1:],rd[:-1]
        f.close()
     
     
    print 'Fichier de départ pour chaque essai :    (deb = position du pointeur avant la lecture de la ligne)'
    f = open('fichierY','w')
    f.write('France: Paris\nAllemagne: Berlin\nAutriche: Vienne\n')
    f.close()
    f = open('fichierY','r')
    while 1:
        p,rd = f.tell(),f.readline()
        print 'deb =',str(p+1000)[1:],
        if not rd:  break
        print rd[:-1]
    f.close()
     
     
    ch = raw_input('\n\nEntrer la chaine à sur-écrire dans ce fichier : ')
    print '\nEtats du fichier apres les traitements indiques'
     
    execution('1', ') sans lecture prealable')
    execution('2', ') f.readline()')
    execution('3', ') sans lecture prealable  ,  p = f.tell()')
    execution('4', ') f.readline()   p = f.tell()')
    execution('5', ') sans lecture prealable  ,  f.seek(18)')
    execution('6', ') f.readline()   f.seek(18)')
    L'écriture n'est possible dans un fichier ouvert en 'r+' que dans deux cas
    - soit juste après l'ouverture du fichier: le pointeur est alors à la position 0 et l'écriture se fait à partir du début du fichier.
    - soit après avoir positionné le pointeur à un endroit quelconque au milieu du fichier au moyen de seek() .

    Les choses sont rendues complexes par le fait que si on fait agir readline() sur le fichier à partir d'une situation où l'écriture est possible, c'est à dire juste après l'ouverture du fichier en 'r+ (cas de 'WEDU' dans exemple) ou après avoir fait seek(n) et write() ( cas de 'HHHHHHHHH' dans exemple), alors on perd la possibilité d'écrire; pour la restaurer, il faut exécuter à nouveau seek(n) une fois.


    Par contre, une fois que la possibilité d'écrire est installée, on peut faire plusieurs write() à la suite
    - même sans seek() : les écritures seront collées les unes à la suite des autres sans espace (cas de 'MMM" dans l'exemple)
    - ou en sautant d'une position à une autre, en avant ou en arrière au sein du fichier avec seek() ( cas de '29' et '18' dans l'exemple)

    Pour ce qui est de la lecture avec readline(), elle n'est pas remise en cause par des séquences d'écriture précédentes, on peut enchainer readline() juste après un write() (cas de la Ligne interne dans l'exemple).


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    def creation_de_xfichierY():
        f = open('xfichierY','w')
        f.write('France: Paris\n')
        f.write('Allemagne: Berlin\n')
        f.write('Autriche: Vienne\n')
        f.close()
     
    def resultat():
        print 'Resultat:\n'
        f = open('xfichierY','r')
        while 1:
            p,rd = f.tell(),f.readline()
            print 'p =',str(p+1000)[1:],
            if not rd:  break
            print rd[:-1]
        f.close()
     
    from os import fsync
     
    print 'Fichier de départ:    (deb = position du pointeur avant la lecture de la ligne)'
    creation_de_xfichierY()
    f = open('xfichierY','r')
    rd = 'go'
    while rd:
        p = f.tell()
        rd = f.readline()
        print 'deb =',str(p+1000)[1:],rd[:-1]
    f.close()
     
    print '============================================================'
     
    creation_de_xfichierY()
    f = open('xfichierY','r+')
     
    rd = f.readline()
    print 'Premiere ligne  :',rd[0:-1]
     
    f.write('WEDU')
    f.flush()
    fsync(f.fileno())
     
    f.seek(4)
    f.write('ZYX')
    f.flush()
    fsync(f.fileno())
     
    f.write('MMM')
    f.flush()
    fsync(f.fileno())
     
    f.seek(29)
    f.write('29')
    f.flush()
    fsync(f.fileno())
     
    f.seek(18)
    f.write('18')
    f.flush()
    fsync(f.fileno())
     
    rd = f.readline()
    print 'Ligne interne :',rd
     
    f.write('FOT')
    f.flush()
    fsync(f.fileno())
     
    f.seek(36)
    f.write('HHHHHHHHH')
    f.flush()
    fsync(f.fileno())
     
    resultat()


    L'intérêt du mode 'r+' est tout de même limité par le fait que l'écriture procède par écrasement:
    on n'écarte pas les bytes pour en glisser des supplémentaires au milieu, on écrase seulement le même nombre de caractères que celui qu'on écrit à partir du point de départ de l'écriture, comme le montre le code suivant. Il faut donc se méfier pour ne pas écrire un plus grand nombre de caractères que la longueur de la chaine qu'on veut corriger.
    Dans ce mode 'r+', la taille du fichier ne change pas entre avant et après l'écriture.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    def creation_de_fichierY():
        f = open('fichierY','w')
        f.write('Allemagne     : Berlin     -  3 400 000 habitants \nAutriche      : Vienne     -  1 600 000 habitants \n')
        f.write('Chili         : Madrid     -  5 500 000 habitants \nFrance        : Paris      - 11 300 000 habitants \n')
        f.write('Mexique       : Tunis      -  2 083 000 habitants \nPays Bas      : Amsterdam  -    739 000 habitants \n')
        f.close()
     
    def affichage_de_fichierY(x):
        print 'fichierY ' + x
        f = open('fichierY','r')
        rd = 'go'
        while rd:
            p,rd = f.tell(), f.readline()
            print 'p =',str(p+1000)[1:],rd[:-1]
        f.close()
     
    capitale = { 'Allemagne     ':'Berlin','Autriche      ':'Vienne','Chili         ':'SANTIAGO DE CHILE',\
                 'France        ':'Paris','Mexique       ':'MEXICO','Pays Bas      ':'Amsterdam'  }
     
    from os import fsync
     
    creation_de_fichierY()
    affichage_de_fichierY('avant traitement :')
     
    f = open('fichierY','r+')
    while 1:
        p,rd = f.tell(), f.readline()[:-1]
        if rd=='':
            break
        if rd[16:27] != capitale[rd[0:14]]: 
            f.seek(p + 16) # <<<<=================
            f.write(capitale[rd[0:14]])
            f.flush()
            fsync(f.fileno())
            f.readline()
    f.close()
     
    affichage_de_fichierY('apres traitement :')

    Pour résumer:

    1) pour écrire dans un fichier ouvert en mode 'r+', il faut impérativement
    - faire write() juste après l'ouverture du fichier ou juste après avoir utilisé seek() ou en recommançant un write() après un précédent
    - il faut faire suivre l'instruction write() de flush() ET fsync().

    2) le mode 'r+' est plus un mode de lecture-correction que de lecture-écriture.

    Tout ceci est valable indifféremment pour une utilisation de write() ou de writelines()


    --------------------------------------------------------


    J'ai fait de mon mieux pour comprendre et vérifier tout ça. J'espère que je n'ai pas fait d'erreur ou de mauvaise compréhension.
    Si tel était le cas, les tutos et manuels seraient bien inspirés de sortir l'accès aux bonnes explications de son ésotérisme actuel.


    Si vous connaissez des pages donnant les explications que j'ai données ci-dessus, je suis intéressé de les connaître et de voir ce qui y est dit. S'il y en a, j'aurais bien aimé les connaître avant pour m'éviter les nombreux et fastidieux essais qu'il m'a fallu faire pour piger.

  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 lire et écrire dans un fichier en mode a ou a+
    La page de blog de John Arbash Meinel
    http://jam-bazaar.blogspot.com/2007/...-r-w-mode.html
    donne le lien
    http://msdn.microsoft.com/en-us/libr...cb(vs.71).aspx
    vers une page donnant d'intéressantes précisions sur les modes d'ouverture de fichier.

    Même si ça concerne des fonctions fopen et _wfopen (de C++ je crois), ce qui y est écrit sur les modes 'a' et 'a+' doit s'appliquer aussi à Python:


    * quand un fichier est ouvert en mode 'a' ou 'a+', toutes les opérations d'écriture s'effectuent à la fin du fichier. Même si le pointeur a été déplacé dans le fichier avec seek(), il est toujours ramené à la fin du fichier avant qu'une quelconque opération d'écriture soit effectuée. Ainsi, les data existantes ne peuvent pas être écrasées.


    * différence entre 'a' et 'a+' :

    -Le mode 'a' n'enlève pas le marqueur EOF avant d'ajouter en fin de fichier. Après que l'ajout de caractères ait eu lieu, la commande MS-DOS TYPE affiche seulement des data jusqu'au marqueur EOF originel et aucune des données qui ont été ajoutées.

    -Le mode 'a+', lui, enlève le marqueur EOF avant d'écrire un ajout. Après un ajout, la commande MS-DOS TYPE affiche toutes les data contenues dans le fichier.
    Le mode 'A+' est requis pour faire des ajouts à un «stream file» qui se termine par le marqueur CTRL+Z EOF

  3. #3
    Membre à l'essai
    Homme Profil pro
    consultant
    Inscrit en
    Novembre 2008
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : consultant

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5
    Par défaut
    Autres particularités avec "r+" et tests sous Linux en python2.5 ou python3.0 :

    - un "open(nom_de_fichier,'r+')" pour créer un fichier qui n'existe pas génère une exception IO : IOError: [Errno 2] No such file or directory: 'nom_de_fichier'.
    - la création puis l'édition d'un fichier en accès aléatoire peut se faire part :
    >>> fb = open('/tmp/fb','ab+')
    - Sous linux l'appel de flush() peut être nécessaire mais pas de fsync()

Discussions similaires

  1. Lire et écrire dans un fichier binaire
    Par poche dans le forum C
    Réponses: 17
    Dernier message: 19/03/2007, 16h52
  2. Lire et écrire dans un fichier bin!
    Par poche dans le forum C
    Réponses: 9
    Dernier message: 12/03/2007, 12h42
  3. lire et écrire dans un fichier
    Par karel dans le forum C
    Réponses: 15
    Dernier message: 18/01/2006, 17h24
  4. [FTP] Lire et écrire dans un fichier
    Par dj-julio dans le forum Langage
    Réponses: 49
    Dernier message: 12/01/2006, 11h59
  5. [Rech. Comp.] Lire et écrire dans des fichiers XML
    Par Rodrigue dans le forum C++Builder
    Réponses: 4
    Dernier message: 26/08/2005, 20h48

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