[Python] os.path.getsize(fichier)>=98000

os.path.getsize(fichier)>=98000 [Python] - Python - Programmation

Marsh Posté le 21-04-2009 à 14:29:31    

Bonjour,
 
je suis débutant en Python et j'ai écrit un script pour résoudre le problème suivant: avec Thunderbird j'ai exporté mon annuaire en un fichier csv. Comme je n'ai la plus part du temps que l'adresse du contact, j'ai un peu moins de 1500 lignes comme celles-ci
 
,,,,machin@student.ulg.ac.be,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
 
or la WebMail dans laquelle je veux importer ce fichier refuse l'importation tant qu'elle n'a pas un nom allant avec l'adresse. De plus, après quelques essais, j'ai compris qu'elle n'acceptait pas les fichiers de plus de 100Ko. Donc j'extrais "machin" de "machin@student.ulg.ac.be" et j'écris machin dans le champ précédent l'adresse e-mail (càd après la 3ème virgule)
 
,,,machin,machin@student.ulg.ac.be,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
 
De plus si mon fichier atteint une taille critique, approchant des 100Ko, je le ferme pour créer un second fichier. Voici ce que mon script donne:
 

Citation :


import os
 
nbrFichiers = 1    #on sera peut-être amenés à créer plusieurs fichiers
fichier = 'FAPSE_modif' + str(nbrFichiers) + '.csv'
fE = open('FAPSE test.csv', 'r')
fS = open(fichier, 'w')
 
#la première ligne décrit les champs, elle gène car est interprétée étant déjà
#le premier contact de la liste par la WebMail de l'ULg, donc on ne l'écrit pas
ligne=fE.readline()
 
nbrAdresses = 0
for ligne in fE:
 
    #dans cette première boucle, on va extraire le nom
    i = 0
    for caractere in ligne:
        if (caractere == ','):
            posVirgule = i
        elif (caractere == '@'):
            nom = ligne[(posVirgule + 1):i]
            break
        i=i+1
             
    #maintenant on écrit la ligne caractère par caractère jusqu'à tomber à
    #l'endroit où on doit insérer le 'nom', càd après la 3ème virgule
    nbrVirgules=0
    for caractere in ligne:
        fS.write(caractere)
        if (caractere==','):
            nbrVirgules = nbrVirgules + 1
            if (nbrVirgules == 3):
                fS.write(nom)
 
    #si le fichier risque de dépasser la limite des 100Ko, on arrête l'écriture
    #dans ce fichier, pour ouvrir le suivant en incrémentant nbrFichiers
    if (os.path.getsize(fichier)>=99000):
        fS.close()
        nbrFichiers = nbrFichiers + 1
        fichier = 'FAPSE_modif' + str(nbrFichiers) + '.csv'
        fS = open(fichier,'w')
   
 
    nbrAdresses = nbrAdresses + 1
 
 
fE.close()
fS.close()
 
message = str(nbrAdresses) + ' enregistrements traités'
print message


 
Voilà. Donc si je ne me trompe pas, le pire cas imaginable, serait si à l'itération 'x' on avait un fichier de 98 999 octets, et qu'à l'itération 'x+1' on devait écrire une ligne de au moins 1001 octets. Dans ce cas on atteindrait les 100Ko. Or une ligne fait rarement plus de 100 octets, la plus longue que j'aie trouvé pèse 105 octets. Donc le fichier devrait faire maximum 99 104 octets...
Or, en pratique, si je laisse ma condition à 99 000:    (os.path.getsize(fichier)>=99000) -> j'obtiens un fichier qui pèse 102 407 octets!
 
Autre test:
 
si je modifie ma condition en "if (os.path.getsize(fichier)>=98000)" -> j'obiens un fichier de 98 357 octets
Ça voudrait dire que, dans le meilleur des cas, à l'itération x j'avais un fichier de 97 999, et j'ai dû écrire une ligne de 358 octets à l'itération x+1
Sachant que la dernière ligne du fichier pèse en fait 77 octets, ce n'est pas elle qui a pu faire dépasser ma limite de 357 octets. On devait avoir déjà dépassé les 98 000 de plusieurs lignes avant que ma condition (os.path.getsize(fichier)>=98000) ne devienne vraie...  :??:  
 
Merci de m'éclairer...
Florimond :)


Message édité par Florimondh le 21-04-2009 à 14:40:25
Reply

Marsh Posté le 21-04-2009 à 14:29:31   

Reply

Marsh Posté le 21-04-2009 à 19:20:43    

Mouais, je ne connais rien à Python, mais je parie que les écritures sont bufferisées. Donc soit tu fais un flush avant de récupérer la taille du fichier, ou alors tu crées un compteur qui ajoute tout ce qui est retourné par "write".

Reply

Marsh Posté le 21-04-2009 à 20:57:22    

tpierron a écrit :

Mouais, je ne connais rien à Python, mais je parie que les écritures sont bufferisées. Donc soit tu fais un flush avant de récupérer la taille du fichier, ou alors tu crées un compteur qui ajoute tout ce qui est retourné par "write".


 
haaa ouiiii, c'est le même principe que dans la communication réseau... les données s'agglomèrent pour en envoyer un certain nombre dans le même paquet... j'avais pas pensé à ça pour l'écriture dans un fichier.
J'ai pu le vérifier en tapant quelques commandes dans l'interpréteur, pour qu'il me les exécutent en temps réel.
 
 Je lui demande de me créer un fichier
 
fichier = open('bonjour','w')
 
là je constate que le fichier est bien créé, et pèse 0 octets
puis je lui demande d'écrire
 
fichier.write('bla bla bla')
 
et après cette instruction, je constate que le fichier pèse toujours 0 octets. Il faut que je fasse un  
 
fichier.close()
 
pour que l'interpréteur écrive ce que je lui avait demandé... et là je peux évidemment constater que le fichier à pris quelques octets
 
 
Je n'ai pas encore trouver comment faire un "flush"
Je pourrais compter moi-même les octets au fur et à mesure que je demande leur écriture, et j'ai déjà essayé, mais c'est pas aussi simple que 1 caractère=1 octets avec l'UTF-8 :(
 
Alors je peux encore demander la fermeture du fichier avant de le réouvrir, et là seulement demander sa taille... mais avoue que c'est pas terriblement esthétique...
Bien sûr je peux aussi mettre ma condition à  
 
if (os.path.getsize(fichier)>=95000)
 
comme ça j'ai une marge de 5000 octets, et je serai probablement tranquille dans tous les cas, mais encore une fois j'aimerais une méthode plus jolie...
 
Je continue à chercher pour le flush...
Merci de ton aide, maintenant je sais ce qu'il se passe... :)

Message cité 1 fois
Message édité par Florimondh le 21-04-2009 à 20:59:32
Reply

Marsh Posté le 21-04-2009 à 21:01:35    

sorry trompé de bouton, faites pas attention à ce message


Message édité par Florimondh le 21-04-2009 à 21:28:17
Reply

Marsh Posté le 21-04-2009 à 21:07:04    

utilise str.split plutot que ton découpage foireux. Tu charges tout dans une list, bien préparée. Dans un deuxième temps, tu écris n fichiers en faisant tout simplement une partition par len(l[x]). Compte combien tu écris et ne fais pas la technique du démineur belge ...

Reply

Marsh Posté le 21-04-2009 à 21:08:33    

et c'est pas flush, c'est sync ...

Reply

Marsh Posté le 21-04-2009 à 22:23:03    

Taz a écrit :

et c'est pas flush, c'est sync ...


Python n'expose pas sync, par contre les objets file ont une méthode flush, dont le but est de commiter le buffer interne. Ca veut pas dire que les données vont arriver au disque, mais ça veut dire qu'elles sont balancées au FS [:spamafote]
 
Accessoirement, les objets file ont une méthode tell permettant de savoir où on en est dans un fichier.
 
Enfin, personnellement j'utiliserais le module CSV, il marche bien [:petrus75]


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 21-04-2009 à 23:15:38    

A travers os si. C'est mal foutu, mais ça y est.

 

Idem pour os.stat. Si tu le fais directement sur ton fd, y a rien besoin de sync. C'est quand même vachement moins couillon de passer par là (ou par tell si t'es à la fin) que de faire des sync, et refaire un os.path.getsize().

 

Toutes façons y a rien besoin de tout ça. Suffit d'écrire en comptant, tant que t'as pas dépassé ta limite, tu continues.

Message cité 1 fois
Message édité par Taz le 21-04-2009 à 23:17:36
Reply

Marsh Posté le 21-04-2009 à 23:50:01    

Alors, merci pour vos réponses. J'ai réécrit mon petit script en utilisant split et le module CSV... c'est vrai que c'est plus efficace  :D  
 

Citation :


import os
import csv
 
#la première ligne décrit les champs, elle gène car est interprétée comme étant
#déjà le premier contact de la liste par la WebMail de l'ULg, donc on la passe
fichierEntree = open('FAPSE.csv', 'r')
fichierEntree.readline()
#on envoie par contre tout ce qui suit la première ligne au reader
fE = csv.reader(fichierEntree.readlines())
fichierEntree.close()
 
nbrFichiers = 1    #on sera peut-être amenés à créer plusieurs fichier
fichier = 'FAPSE_modif' + str(nbrFichiers) + '.csv'
fichierSortie = open(fichier, 'w')
fS = csv.writer(fichierSortie)
 
 
nbrAdresses = 0
for ligne in fE:
 

    nomETdomaine = ligne[4].split('@')
    ligne[3] = nomETdomaine[0]
    fS.writerow(ligne)

     
    #si le fichier risque de dépasser la limite des 100Ko, on arrête l'écriture
    #dans ce fichier, pour ouvrir le suivant en incrémentant nbrFichiers
    if (os.path.getsize(fichier)>=98000):
        nbrFichiers = nbrFichiers + 1
        fichierSortie.close()
        fichier = 'FAPSE_modif' + str(nbrFichiers) + '.csv'
        fichierSortie = open(fichier, 'w')
        fS = csv.writer(fichierSortie)
 
    nbrAdresses = nbrAdresses + 1
 
fichierSortie.close()
 
message = str(nbrAdresses) + ' enregistrements traités'
print message


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

Taz a écrit :

A travers os si. C'est mal foutu, mais ça y est.
 
Idem pour os.stat. Si tu le fais directement sur ton fd, y a rien besoin de sync. C'est quand même vachement moins couillon de passer par là (ou par tell si t'es à la fin) que de faire des sync, et refaire un os.path.getsize().
 
Toutes façons y a rien besoin de tout ça. Suffit d'écrire en comptant, tant que t'as pas dépassé ta limite, tu continues.


 
Par contre, il semble qu'il ne suffise pas de compter le nombre de caractères dont je demande l'écriture pour avoir la taille du fichier. En effet, si mon fichier de sortie compte 97 146 caractères, il pèse pourtant 98 375 octets. UTF-8 sans doute.
Et je ne m'y retrouve pas bien entre les "os.stat", les "sync", les "tell" ... mais je vais continuer à chercher.
 
Plus haut tu écrivais "Compte combien tu écris et ne fais pas la technique du démineur belge ..." - je suis curieux de savoir ce qu'est la "technique du démineur belge"  :whistle:

Message cité 1 fois
Message édité par Florimondh le 21-04-2009 à 23:52:27
Reply

Marsh Posté le 21-04-2009 à 23:51:17    

j'ai essayé os.fsync mais ça n'a pas changé grand chose


Message édité par Florimondh le 21-04-2009 à 23:54:32
Reply

Marsh Posté le 21-04-2009 à 23:51:17   

Reply

Marsh Posté le 22-04-2009 à 00:09:31    

os.fstat(fichierSortie.fileno()) va te donner la bonne information.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed