Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Optimisation

14 views
Skip to first unread message

pil91

unread,
Sep 10, 2008, 10:21:31 AM9/10/08
to
Bonjour, j'ai besoin de transformer en format csv délimité, des
fichiers fixes.
Le problème c'est que ces fichiers peuvent être très gros, plusieurs
millions de lignes et plusieurs milliers de caractères par ligne.
J'ai donc écrit ce code sous windows en Python 2.5.2, qui, je pense
pourrait être bien optimisé.
Merci d'avance pour vos suggestions.

=========
# _*_ coding: utf8 _*_
#!/usr/bin/env python
# Auteur : Philippe Lotton
# Date de création:

import sys
import datetime
if __name__ == '__main__':
args = sys.argv[1:]
if len(args) == 2: # 2 paramètres obligatoires
fic_entree = args[0] # Fichier source
fic_format = args[1] #Fichier format
else:
print '''Vous devez passez 2 arguments, le fichier source et
le fichier paramètre
ex: csv.py MonFic.txt MonFormat.txt
Le fichier source doit avoir des enregistrements de longueurs
fixes.
Le fichier format doit ètre de la forme: position , longueur
<rc>,
autant de ligne que de champs dans le fichier source.
'''
exit()
print datetime.datetime.now().time()
fic_param = open('format.txt', "r") # Lecture du fichier
paramètre
format = fic_param.readlines() # Création tableaux
des paramètres
fic_param.close()

fic_out = open('csv.txt', 'w') #Ouverture fichier de sortie

fic_source = open(fic_entree, 'r') # Lecture du fichier
source
while 1: #
ligne_source = fic_source.readline()
if ligne_source =='':
break
else :
ligne_cible = '' # Ligne de sortie écrite dans
le fichier
for j in format:
params = j.split(',') #Création d'un
tableau de paramètres
pos1 = int(params[0])-1 #Position 1
pos2 = pos1 + int(params[1]) #Position 2
temp = ligne_source[ pos1:pos2]
ligne_cible = ligne_cible + temp + ',' #
Concaténation
ligne_cible = ligne_cible[0:-1]
fic_out.write(ligne_cible + "\n")
ligne_cible = ''
fic_source.close()
fic_out.close()
print datetime.datetime.now().time()
exit()

Christophe

unread,
Sep 10, 2008, 11:03:44 AM9/10/08
to
pil91 a écrit :

> Bonjour, j'ai besoin de transformer en format csv délimité, des
> fichiers fixes.
> Le problème c'est que ces fichiers peuvent être très gros, plusieurs
> millions de lignes et plusieurs milliers de caractères par ligne.
> J'ai donc écrit ce code sous windows en Python 2.5.2, qui, je pense
> pourrait être bien optimisé.
> Merci d'avance pour vos suggestions.
>
> =========
> # _*_ coding: utf8 _*_
> #!/usr/bin/env python
> # Auteur : Philippe Lotton
> # Date de création:
>
> import sys
> import datetime

C'est pas une suggestion d'optim (enfin, ça pourrait le devenir) mais y
a-t-il une raison pour laquelle vous n'utilisez pas le module standard
csv ? Au début, je pensais que vous aviez écrit votre solution pour
justement être plus performant mais en regardant le source de csv.py, je
constate que celui-ci délègue la majorité du travail à un module et C.

En fait si, c'est bien une suggestion d'optim après tout.

Bruno Desthuilliers

unread,
Sep 10, 2008, 11:26:17 AM9/10/08
to
pil91 a écrit :

> Bonjour, j'ai besoin de transformer en format csv délimité, des
> fichiers fixes.
> Le problème c'est que ces fichiers peuvent être très gros, plusieurs
> millions de lignes et plusieurs milliers de caractères par ligne.
> J'ai donc écrit ce code sous windows en Python 2.5.2, qui, je pense
> pourrait être bien optimisé.

> Merci d'avance pour vos suggestions.
>
> =========
> # _*_ coding: utf8 _*_
> #!/usr/bin/env python
> # Auteur : Philippe Lotton
> # Date de création:
>
> import sys
> import datetime
> if __name__ == '__main__':

Déjà, découpe ton code en fonctions.

> args = sys.argv[1:]
> if len(args) == 2: # 2 paramètres obligatoires
> fic_entree = args[0] # Fichier source
> fic_format = args[1] #Fichier format
> else:
> print '''Vous devez passez 2 arguments, le fichier source et
> le fichier paramètre
> ex: csv.py MonFic.txt MonFormat.txt
> Le fichier source doit avoir des enregistrements de longueurs
> fixes.
> Le fichier format doit ètre de la forme: position , longueur
> <rc>,
> autant de ligne que de champs dans le fichier source.
> '''

les messages d'erreurs devraient aller sur la sortie d'erreur, pas sur
la sortie standard. Donc, print >> sys.stderr.

Ceci étant, puisque sys.exit(msg) écrit le message sur stderr, tu peux
tout simplement passer ton message à sys.exit().

> exit()
> print datetime.datetime.now().time()
> fic_param = open('format.txt', "r") # Lecture du fichier
> paramètre

Pas la peine de commenter chaque ligne avec une paraphrase du code. On
est capable de lire le code. Si ton commentaire n'apporte rien, ne
commente pas.

Accessoirement, je suppose que tu veux:
fic_param = open(fic_format)

Et là, il apparaît que tu utilises la même convention de nommage pour
des chemins de fichier et des objets fichier. Combien de temps avant que
tu ne t'embrouilles, à ton avis ?

> format = fic_param.readlines()

> fic_param.close()
>
> fic_out = open('csv.txt', 'w')

> fic_source = open(fic_entree, 'r')

> while 1:

> ligne_source = fic_source.readline()
> if ligne_source =='':
> break
> else :

Les fichiers en lecture sont leur propre itérateur. Ca t'évite un test,
au passage...

for ligne_source in fic_source:


> ligne_cible = '' # Ligne de sortie écrite dans
> le fichier
> for j in format:
> params = j.split(',') #Création d'un
> tableau de paramètres
> pos1 = int(params[0])-1 #Position 1
> pos2 = pos1 + int(params[1]) #Position 2

T'a pas l'impression que refaire ces calculs à chaque ligne du fichier
source est une perte de temps phénoménale ? Parse le tout avant d'entrer
dans la boucle, tu gagnera du temps.

> temp = ligne_source[ pos1:pos2]
> ligne_cible = ligne_cible + temp + ',' #
> Concaténation

A éviter, tout particulièrement sous cette forme (la forme 'ligne +=
truc' est optimisée dans les versions récentes de CPython, mais ça reste
une mauvaise solution).

La bonne façon de faire est de stocker les champs dans une liste, et
faire un ",".join(laliste) à la fin.

> ligne_cible = ligne_cible[0:-1]

ce qui évite aussi ça...


> fic_out.write(ligne_cible + "\n")
> ligne_cible = ''

cette dernière instruction est inutile, tu le fais déjà au début de la
boucle.

> fic_source.close()
> fic_out.close()
> print datetime.datetime.now().time()
> exit()
>


Correction possible, mais Q&D et pas très robuste. J'ai gardé ton
nommage mais tu devrais le corriger. NB : pas testé.

import sys
import datetime

def parse_params(lines):
params = []
for line in enumerate(lines):
line = line.strip()
if not line:
continue
parts = line.split(',')
pos1 = int(parts[0])-1
pos2 = pos1 + int(parts[1])
params.append(slice(pos1, pos2))
return params


def do_import(params, fic_source, fic_out):
write = fic_out.write
sep = ','
join = sep.join # evite un lookup
for ligne_source in fic_source:
ligne_cible = [ligne_source[slice] for slice in params]
write(join(ligne_cible) + "\n")

def main(args):
try:
fic_entree, fic_format = args
except ValueError:
sys.exit('''Vous devez passez 2 arguments, le fichier source et


le fichier paramètre
ex: csv.py MonFic.txt MonFormat.txt
Le fichier source doit avoir des enregistrements de longueurs
fixes.
Le fichier format doit ètre de la forme: position , longueur
<rc>,
autant de ligne que de champs dans le fichier source.

''')

# XXX : gérer le cas d'une exception durant le parsing
fic_param = open(fic_format)
params = parse_param(fic_param)
fic_params.close()

# XXX : gérer le cas d'une erreur lors de l'ouverture de fic_out


fic_source = open(fic_entree, 'r')

fic_out = open('csv.txt', 'w')

try:
do_import(params, fic_source, fic_out)
finally:
fic_source.close()
fic_out.close()

if __name__ == '__main__':
print >> sys.stderr, datetime.datetime.now().time()
main(sys.argv[1:])
print >> sys.stderr, datetime.datetime.now().time()

HTH

Bruno Desthuilliers

unread,
Sep 10, 2008, 11:27:57 AM9/10/08
to
Christophe a écrit :

> pil91 a écrit :
>> Bonjour, j'ai besoin de transformer en format csv délimité, des
>> fichiers fixes.
(snip)

> C'est pas une suggestion d'optim (enfin, ça pourrait le devenir) mais y
> a-t-il une raison pour laquelle vous n'utilisez pas le module standard
> csv ?

Peut-être le fait que le format csv soit la cible, pas la source ?-)

Christophe

unread,
Sep 10, 2008, 11:28:56 AM9/10/08
to
Bruno Desthuilliers a écrit :

Et ? Le module csv fait lecture et écriture.

Help on module csv:

NAME
csv - CSV parsing and writing.

FILE
c:\python25\lib\csv.py

DESCRIPTION
This module provides classes that assist in the reading and writing
of Comma Separated Value (CSV) files, and implements the interface
(...)

pil91

unread,
Sep 10, 2008, 11:31:53 AM9/10/08
to

Je pensais améliorer les choses en remplacant la concaténation de ma
chaine un append dans un tableau, puis un join
----
else :
sortie = []


for j in format:
params = j.split(',') #Création d'un
tableau de paramètres
pos1 = int(params[0])-1 #Position 1
pos2 = pos1 + int(params[1]) #Position 2
temp = ligne_source[ pos1:pos2]

sortie.append(temp)
result = ','.join(sortie)
out.write(result + "\n")
sortie = []
fic_source.close()
out.close()
---
Excès d'autosatisfaction, c'est quif quif, 18s, sur 1 000 000
d'enregistrement avec cette structure
------
aaaaaaaaaaabbbbwyyyyyyyyyyyyyyy
tttttttttttppppbqqqqqqqqqqqqqqq
rrrrrrrrrrrhhhhkeeeeeeeeeeeeeee
-------
@Christophe
Oui c'est vrai le module csv, ben... j'ai essayé de l'importer et puis
après je suis passé à autre chose.
Quand je lancais l'exécution j'obtenais un message 'module object has
no attribute reader.


Christophe

unread,
Sep 10, 2008, 11:40:09 AM9/10/08
to
pil91 a écrit :

> @Christophe
> Oui c'est vrai le module csv, ben... j'ai essayé de l'importer et puis
> après je suis passé à autre chose.
> Quand je lancais l'exécution j'obtenais un message 'module object has
> no attribute reader.


Ah mais chez moi il marche très bien :) Si le module était cassé à ce
point, ça se saurait.

Allez, je parie qu'il y a un petit fichier csv.py ou csv.pyc qui traine
pas loin et qui cache le module officiel.

pil91

unread,
Sep 10, 2008, 11:45:26 AM9/10/08
to

@Bruno Desthuilliers
Merci pour ce cours magistral, je revois ma copie demain :).
Effectivement l'utilisation du module csv serait plus orthodoxe et
efficace.

Bruno Desthuilliers

unread,
Sep 10, 2008, 11:48:58 AM9/10/08
to
Christophe a écrit :

> Bruno Desthuilliers a écrit :
>> Christophe a écrit :
>>> pil91 a écrit :
>>>> Bonjour, j'ai besoin de transformer en format csv délimité, des
>>>> fichiers fixes.
>> (snip)
>>
>>> C'est pas une suggestion d'optim (enfin, ça pourrait le devenir) mais
>>> y a-t-il une raison pour laquelle vous n'utilisez pas le module
>>> standard csv ?
>>
>> Peut-être le fait que le format csv soit la cible, pas la source ?-)
>
> Et ? Le module csv fait lecture et écriture.

Oui. Il lit effectivement des csv. Ce qui n'est pas le cas des fichiers
sources de l'OP, ni la source de son problème.

>
>
> Help on module csv:
>
> NAME
> csv - CSV parsing and writing.
>
> FILE
> c:\python25\lib\csv.py
>
> DESCRIPTION
> This module provides classes that assist in the reading and writing
> of Comma Separated Value (CSV) files, and implements the interface
> (...)

Merci, c'est gentil, je ne l'utilise qu'une cinquantaine de fois par an,
ce module...

Bruno Desthuilliers

unread,
Sep 10, 2008, 11:59:58 AM9/10/08
to
pil91 a écrit :
(snip)

> Effectivement l'utilisation du module csv serait plus orthodoxe et
> efficace.

Pour l'écriture, éventuellement, et encore seulement pour des trucs un
peu complexes (quotes etc). Pour la lecture, je doute... Si j'ai bien
compris, chaque ligne de ton fichier source est composé de X champs,
chaque champ ayant une taille (fixe) differente. Si oui, ça n'a aucun
rapport avec un format csv, donc...

Christophe

unread,
Sep 10, 2008, 12:48:12 PM9/10/08
to
Bruno Desthuilliers a écrit :
> Christophe a écrit :
>> Bruno Desthuilliers a écrit :
>>> Christophe a écrit :
>>>> pil91 a écrit :
>>>>> Bonjour, j'ai besoin de transformer en format csv délimité, des
>>>>> fichiers fixes.
>>> (snip)
>>>
>>>> C'est pas une suggestion d'optim (enfin, ça pourrait le devenir)
>>>> mais y a-t-il une raison pour laquelle vous n'utilisez pas le module
>>>> standard csv ?
>>>
>>> Peut-être le fait que le format csv soit la cible, pas la source ?-)
>>
>> Et ? Le module csv fait lecture et écriture.
>
> Oui. Il lit effectivement des csv. Ce qui n'est pas le cas des fichiers
> sources de l'OP, ni la source de son problème.


Ah, je m'excuse, j'avais mal vu l'énoncé et je confondais le format du
fichier de format avec le format du fichier d'entrée de données. Comme
quoi il est mal de répondre à ce genre de questions pendant les heures
de travail (même pendant une pause) : on va trop vite et on rate des
choses importantes :)

Christophe

unread,
Sep 10, 2008, 12:53:09 PM9/10/08
to
pil91 a écrit :

> On 10 sep, 17:03, Christophe <chris.cavala...@free.fr> wrote:
>> pil91 a écrit :
>>
>>
>>
>>> Bonjour, j'ai besoin de transformer en format csv délimité, des
>>> fichiers fixes.
>>> Le problème c'est que ces fichiers peuvent être très gros, plusieurs
>>> millions de lignes et plusieurs milliers de caractères par ligne.
>>> J'ai donc écrit ce code sous windows en Python 2.5.2, qui, je pense
>>> pourrait être bien optimisé.
>>> Merci d'avance pour vos suggestions.
>>> =========
>>> # _*_ coding: utf8 _*_
>>> #!/usr/bin/env python
>>> # Auteur : Philippe Lotton
>>> # Date de création:
>>> import sys
>>> import datetime
>> C'est pas une suggestion d'optim (enfin, ça pourrait le devenir) mais y
>> a-t-il une raison pour laquelle vous n'utilisez pas le module standard
>> csv ? Au début, je pensais que vous aviez écrit votre solution pour
>> justement être plus performant mais en regardant le source de csv.py, je
>> constate que celui-ci délègue la majorité du travail à un module et C.
>>
>> En fait si, c'est bien une suggestion d'optim après tout.
>
> Je pensais améliorer les choses en remplacant la concaténation de ma
> chaine un append dans un tableau, puis un join
(...)

> Excès d'autosatisfaction, c'est quif quif, 18s, sur 1 000 000
> d'enregistrement avec cette structure

Ah oui, à ce sujet l'implémentation CPython optimise automatiquement les
longues suites de concaténations dans une même string de la façon dont
tu le fais. Avec une version un peu plus ancienne de Python, tu aurais
certainement vu une très grande amélioration.

Bruno Desthuilliers

unread,
Sep 10, 2008, 11:36:40 AM9/10/08
to

Pas de blème, ça arrive à tout le monde (moi le premier...) !-)

Bruno Desthuilliers

unread,
Sep 10, 2008, 12:06:56 PM9/10/08
to
Christophe a écrit :
> pil91 a écrit :
(snip)

>> Je pensais améliorer les choses en remplacant la concaténation de ma
>> chaine un append dans un tableau, puis un join
> (...)
>> Excès d'autosatisfaction, c'est quif quif, 18s, sur 1 000 000
>> d'enregistrement avec cette structure
>
> Ah oui, à ce sujet l'implémentation CPython optimise automatiquement les
> longues suites de concaténations dans une même string de la façon dont
> tu le fais.

Plus ou moins... la version avec un assignement augmenté (s += xxx) est
un poil plus rapide que celle avec un réassignement (s = s + xxx)

Un petit bench valant mieux qu'un long discours:

from timeit import Timer
repeat = xrange(100000)

def concat():
s = ''
for i in repeat:
s = s + 'aaaaa'

def concat_aug():
s = ''
for i in repeat:
s += 'aaaaa'

def append_join():
s = []
for i in repeat:
s.append('aaaaa')
s = ''.join(s)

def local_append_join():
s = []
append = s.append
for i in repeat:
append('aaaaa')
s = ''.join(s)

def comp_join():
s = ''.join('aaaaa' for i in repeat)

timers = [
(funcname, Timer('%s()' % funcname, 'from __main__ import %s' %
funcname))
for funcname in ('concat', 'concat_aug', 'append_join',
'local_append_join', 'comp_join')
]

for funcname, t in timers:
print funcname, t.timeit(100)


Résultats ici (python 2.5.1 sous gentoo-linux):

concat 3.99100494385
concat_aug 3.96803593636
append_join 6.26043510437
local_append_join 3.67693090439
comp_join 3.72800898552

Le mauvais résultat de append_join par rapport à local_append_join
s'explique par le hit dû au lookup de list.append, suivi de
l'instanciation de l'objet méthode. Comme quoi cette simple optimisation
(localiser les methodes appelées dans une boucle 'intensive') est très
payante. Par contre, dans le cas de l'OP, je ne sais pas si ce sera
vraiment plus intéressant (pour la boucle intérieure de do_import) dans
la mesure où c'est, justement dans une boucle imbriquée. Mais bon, pil,
tu peux tester les deux... AMHA, selon le jeu d'essai (données sources),
tu aura des résultats en faveur tantôt de la solution local_append_join,
tantôt en faveur de la solution comp_join.

> Avec une version un peu plus ancienne de Python, tu aurais
> certainement vu une très grande amélioration.

Aucun doute....

Bruno Desthuilliers

unread,
Sep 10, 2008, 12:12:27 PM9/10/08
to
pil91 a écrit :
(snip)

> Je pensais améliorer les choses en remplacant la concaténation de ma
> chaine un append dans un tableau, puis un join


> ----
> else :
> sortie = []
> for j in format:
> params = j.split(',') #Création d'un
> tableau de paramètres
> pos1 = int(params[0])-1 #Position 1
> pos2 = pos1 + int(params[1]) #Position 2
> temp = ligne_source[ pos1:pos2]
> sortie.append(temp)

Tu gagnerais beaucoup en 'localisant' la méthode append, cf mon autre
post en réponse à Christophe.

> result = ','.join(sortie)
> out.write(result + "\n")
> sortie = []
> fic_source.close()
> out.close()
> ---
> Excès d'autosatisfaction, c'est quif quif, 18s, sur 1 000 000
> d'enregistrement avec cette structure

Ce que je trouve amusant, c'est que tu n'ai toujours pas vu
ce qui est très probablement le problème majeur de ton code !-)

Rakotomandimby (R12y) Mihamina

unread,
Sep 10, 2008, 4:58:25 PM9/10/08
to
Bruno Desthuilliers wrote:
> Ce que je trouve amusant, c'est que tu n'ai toujours pas vu
> ce qui est très probablement le problème majeur de ton code !-)

Sérieusement:
- le nommage des variables?
- les commentaires qui en remettent une couche?
- l'absence de fonctions?

Il est tard, je ne vois pas non plus :-)

--
Serveurs infogérés:
http://www.infogerance.us/infogerance/packs-serveurs-infogeres

Méta-MCI (MVP)

unread,
Sep 10, 2008, 5:27:45 PM9/10/08
to
Bonsoir !

C'est peut-être hors sujet, mais, perso, lorsque j'utilise des fichiers
avec enregistrements à longueur fixe, il n'y a pas de notion de
ligne(s). Les données sont toutes accolées, sans séparateurs, ni de
champs, ni d'enregistrements.

Du coup, j'ai modifié un peu ton exemple, en ce sens. Voir ci-dessous
(mais, il faut que ça rentre en mémoire).

> NB : pas testé.
J'ai, vu. Moi, j'ai testé, et j'ai corrigé deux ou trois détails.

Par contre, pour l'optimisation, je voulais comparer read() total et
read(size) ; mais, avec 1 million d'enregistrements, sur mon Vista, ça
ne prend que 3 secondes, alors...

@+
--
MCI


# -*- coding: utf-8 -*-

import sys
import datetime

def parse_params(lines):
params = []
for line in lines:


line = line.strip()
if not line:
continue
parts = line.split(',')
pos1 = int(parts[0])-1
pos2 = pos1 + int(parts[1])
params.append(slice(pos1, pos2))

return params,pos2


def do_import(params, longenregistrement, fic_source, fic_out):


write = fic_out.write
sep = ','
join = sep.join

data_source=fic_source.read()
data=(data_source[i:i+longenregistrement] for i in
range(0,len(data_source),longenregistrement))
for ligne_source in data:


ligne_cible = [ligne_source[slice] for slice in params]
write(join(ligne_cible) + "\n")


def main(*args):
fic_entree="MonFic.txt"
fic_format="MonFormat.txt"


"""
try:
fic_entree, fic_format = args
except ValueError:
sys.exit('''Vous devez passez 2 arguments, le fichier source et
le fichier paramètre
ex: csv.py MonFic.txt MonFormat.txt
Le fichier source doit avoir des enregistrements de longueurs
fixes.
Le fichier format doit ètre de la forme: position , longueur
<rc>,
autant de ligne que de champs dans le fichier source.
''')
"""


# XXX : gérer le cas d'une exception durant le parsing
fic_param = open(fic_format)

params,longenregistrement = parse_params(fic_param) #+++
fic_param.close() #+++

# XXX : gérer le cas d'une erreur lors de l'ouverture de fic_out
fic_source = open(fic_entree, 'r')
fic_out = open('csv.txt', 'w')
try:

do_import(params, longenregistrement, fic_source, fic_out)
finally:
fic_source.close()
fic_out.close()

if __name__ == '__main__':
print >> sys.stderr, datetime.datetime.now().time()

main()
print >> sys.stderr, datetime.datetime.now().time()


Bruno Desthuilliers

unread,
Sep 11, 2008, 4:21:17 AM9/11/08
to
Rakotomandimby (R12y) Mihamina a écrit :

> Bruno Desthuilliers wrote:
>> Ce que je trouve amusant, c'est que tu n'ai toujours pas vu
>> ce qui est très probablement le problème majeur de ton code !-)
>
> Sérieusement:
> - le nommage des variables?
> - les commentaires qui en remettent une couche?
> - l'absence de fonctions?

Ce sont effectivement trois problèmes, mais le seul à avoir un impact
(probablement mineur) sur les perfs est le troisième. Mais non, ce n'est
pas de ça qu'il s'agit.

> Il est tard, je ne vois pas non plus :-)

T'a pas l'impression qu'il y a un calcul qui pourrait être extrait de la
boucle sur le fichier source ?

Alain BARTHE

unread,
Sep 12, 2008, 7:16:23 AM9/12/08
to

Je pense que tu pourrais aussi utiliser le module struct, qui semble
mieux adapté pour ton problème.

Principe :
- définir une format décrivant la structure de tes enregistrements:

Exemple : Si ton enregistrement contient :
nom 30 caractères
prenom 20 caractères
tel 10 entiers

Tu crées un format = "30s20s10i"

import struct

format = "30s20s10i"
size = struct.calcsize (format)

in = open ("fichier.dat", "r")
out = open ("fichier.csv", "w")

while f:
data = in.read (size)
nom, prenom, tel = struct.unpack (format, data)

print >> out, "%s,%s,%d;", % (nom,prenom,tel)

in.close()
out.close()

A tester et vérifier, car je n'ai pas trop le temps maintenant, mais ca
me semble une solution plus adaptée à ton besoin.

Par contre, je ne sais pas si ce sera plus efficace.


Bruno Desthuilliers

unread,
Sep 12, 2008, 9:07:24 AM9/12/08
to
Alain BARTHE a écrit :
(snip)

> Je pense que tu pourrais aussi utiliser le module struct, qui semble
> mieux adapté pour ton problème.

doh :(

C'est ça le problème avec Python : y a tellement de trucs dans la biblio
standard qu'on oublie fréquemment de vérifier si y a pas déjà une bonne
soluce quelque part...

> Principe :
> - définir une format décrivant la structure de tes enregistrements:
>
> Exemple : Si ton enregistrement contient :
> nom 30 caractères
> prenom 20 caractères
> tel 10 entiers
>
> Tu crées un format = "30s20s10i"
>
> import struct
>
> format = "30s20s10i"
> size = struct.calcsize (format)
>
> in = open ("fichier.dat", "r")
> out = open ("fichier.csv", "w")
>
> while f:
> data = in.read (size)

Attention, s'il y a des newlines en fin d'enregistrement, il faut en
tenir compte dans la taille (et probablement dans le struct), en tenant
compte des problèmes de portabilité entre plateformes pour le format des
newlines.

> nom, prenom, tel = struct.unpack (format, data)
>
> print >> out, "%s,%s,%d;", % (nom,prenom,tel)
>
> in.close()
> out.close()

(snip)


> Par contre, je ne sais pas si ce sera plus efficace.

<OP>
Pil, si tu tentes cette solution, je veux bien savoir le résultat (si ça
fonctionne pour ton cas, et si oui si c'est plus performant).
</OP>

Alain BARTHE

unread,
Sep 12, 2008, 11:07:03 AM9/12/08
to
Bruno Desthuilliers a écrit :

On peut ajouter le motif x (padding) dans le format pour prendre en
compte le \n ou même ignorer un champ dont on n'a pas besoin.

>> nom, prenom, tel = struct.unpack (format, data)
>>
>> print >> out, "%s,%s,%d;", % (nom,prenom,tel)
>>
>> in.close()
>> out.close()
>
> (snip)
>> Par contre, je ne sais pas si ce sera plus efficace.
>
> <OP>
> Pil, si tu tentes cette solution, je veux bien savoir le résultat (si ça
> fonctionne pour ton cas, et si oui si c'est plus performant).
> </OP>

Concernant le fonctionnement, je pense que ça correspond bien avec son
problème. Je n'ai pas pu tester réellement car je n'avais pas le temps
de me créer un fichier de test, mais le module semble fait pour.

Pour les perf, j'espère que ça doit être meilleur, le module semble être
un .so dont probablement être écrit en C et la découpe des divers champs
devrait être plus efficace qu'avec du code Python.

A confirmer quand même.

Alain BARTHE

unread,
Sep 12, 2008, 11:42:28 AM9/12/08
to
Alain BARTHE a écrit :

> Bruno Desthuilliers a écrit :
>> Alain BARTHE a écrit :
>> (snip)
>>> Je pense que tu pourrais aussi utiliser le module struct, qui semble
>>> mieux adapté pour ton problème.
>>
>> doh :(
>>
>> C'est ça le problème avec Python : y a tellement de trucs dans la
>> biblio standard qu'on oublie fréquemment de vérifier si y a pas déjà
>> une bonne soluce quelque part...
>>
>>> Principe :
>>> - définir une format décrivant la structure de tes enregistrements:
>>>
>>> Exemple : Si ton enregistrement contient :
>>> nom 30 caractères
>>> prenom 20 caractères
>>> tel 10 entiers
>>>

Je me suis planté dans la syntaxe du format : 10i indique un tableau de
10 entiers codés en binaire selon la plateforme (4 octets sur ma machine)

On peut utiliser hHiIlL (pour short, int, long signés ou non) et même
précéder de @=<> pour préciser les types de plateformes et d'endianess.

pil91

unread,
Sep 13, 2008, 3:29:28 AM9/13/08
to

Juste un msg pous vous dire que je suis le fil, que vous enrichissez.
Je n'ai pas eu beaucoup de temps, mais je reprends tout ça la semaine
prochaine et je vous fait remonter les résultats.
Bon week-end

0 new messages