Lire et écrire dans un fichier
Comme il existe un objet int
ou float
il existe également un objet
file
. Pour lire
et écrire dans un fichier il faut donc apprendre à utiliser cet objet.
La fonction open()
Avant de lire et écrire dans un fichier on dit qu'on "ouvre" ce fichier. Cette
étape passe par la fonction
open()
qui crée un
objet file
.
Lorsqu'on travaille avec un fichier, il est préférable de s'assurer que certaines opérations sont exécutées avant et après l'ouverture. Pour ce faire on utilise un contexte. Il permet de séparer un bloc d’instructions donné. Python se charge alors d'exécuter des opérations de contrôle avant et après le bloc d'instructions.
Voici la syntaxe :
with objet as alias:
# instructions sur alias
Lors de la création de alias et après l'exécution des instructions le concernant python fait le nécessaire pour nous simplifier la gestion de certaines erreurs.
On se donne un fichier donnees.dat
:
# titre du fichier
1. 2.1
2. 2.9
3. 4.2
4. 5.05
5. 5.85
6. 6.95
7. 8.1
8. 9.
9. 10.2
10. 10.9
On va donc écrire :
>>> with open("donnees.dat", "r") as f:
... contenu = f.read()
>>> print(contenu)
# titre du fichier
1. 2.1
2. 2.9
3. 4.2
4. 5.05
5. 5.85
6. 6.95
7. 8.1
8. 9.
9. 10.2
10. 10.9
On a utilisé la méthode read()
pour lire tout le contenu du fichier.
La fonction open()
:
- Le premier argument est le nom du fichier (son chemin pour être précis)
- Le second argument donne le mode d'accès :
"r"
pour read, lecture du fichier"w"
pour write, écriture du fichier"a"
pour append, écriture à la fin du fichier
Lecture ligne par ligne
On va maintenant lire ligne par ligne le fichier pour récupérer dans une liste la première colonne (x) et dans une autre liste la deuxième colonne (y).
with open("donnees.dat", "r") as f:
x = list()
y = list()
for line in f:
if "#" in line:
# on saute la ligne
continue
data = line.split()
x.append(data[0])
y.append(data[1])
print(x)
print(y)
['1.', '2.', '3.', '4.', '5.', '6.', '7.', '8.', '9.', '10.']
['2.1', '2.9', '4.2', '5.05', '5.85', '6.95', '8.1', '9.', '10.2', '10.9']
Remarques :
- La fonction
split()
découpe une chaîne de caractères suivant les espaces qu'elle contient. - L'instruction
continue
impose à la boucle de passer à l'itération suivante sans exécuter les instructions suivantes. - On remarquera que la liste contient des chaines de caractères qu'il faudrait
convertir en nombre flottant avec la fonction
float()
.
D'autres méthodes existent : readlines()
lit toutes les lignes et retourne
une liste :
with open("donnees.dat", "r") as f:
lines = f.readlines()
print(lines)
['1. 2.1\n', '2. 2.9\n', '3. 4.2\n', '4. 5.05\n', '5. 5.85\n', '6. 6.95\n',
'7. 8.1\n', '8. 9.\n', '9. 10.2\n', '10. 10.9\n']
On pourra se servir de strip()
qui supprime les caractères spéciaux dans la
chaine de caractères.
Nous verrons dans la partie sur numpy qu'il existe une façon très efficace de lire un fichier de ce type.
Écrire un fichier
Essayons par exemple de calculer les valeurs d'une fonction et d'écrire les
résultats dans un fichier. La méthode write()
attend une chaîne de caractères.
def fonction(x):
return 2 * x**2 - 9 * x + 4
x = range(-5, 6, 1)
with open("valeurs.dat", "w") as f:
f.write("# Un titre\n")
for xi in x:
valeurs = "%12.6f %12.6f\n" % (xi, fonction(xi))
f.write(valeurs)
Dans la boucle, xi
et fonction(xi)
sont convertis en chaînes de caractères
avec l'utilisation d'un
format.
On aurait pu simplement écrire str(xi)
et
str(fonction(xi))
mais il faut penser à mettre un espace entre les deux. Le
format %12.6f
indique qu'on va écrire un nombre flottant, f
, sur 12
caractères, avec 6 chiffres après la virgule.
Note : On n'oubliera pas le caractère de fin de ligne \n
, sinon
python ajoute le texte à la suite. Il ne passe pas à la ligne suivante après
chaque appel à la méthode write()
.
Autre solution : nous allons écrire toutes les valeurs dans une chaîne de caractères puis écrire cette chaîne dans le fichier.
def fonction(x):
return 2 * x**2 - 9 * x + 4
x = range(-5, 6, 1)
lines = "# Un titre÷\n"
for xi in x:
lines += "%12.6f %12.6f\n" % (xi, fonction(xi))
with open("valeurs.dat", "w") as f:
f.write(lines)
Extraire des données
Le code suivant présente deux techniques pour extraire des données d'un fichier. Nous allons travailler sur le fichier soup.txt qui est affiché ci-dessous.
Combinons un test et split()
Premier cas simple
L'objectif est de rechercher la valeur de l'énergie écrite sur la ligne 39 du
fichier soup.txt
.
SCF Done: E(RPBE-PBE) = -548.263942119 A.U. after 14 cycles
Voici le code d'une fonction qui renvoie cette énergie :
def read_SCF(fichier):
""" Lit la ligne SCF Done dans le fichier et retourne l'énergie """
with open(fichier, "r") as f:
for line in f:
if "SCF Done:" in line:
mots = line.split()
energie = float(mots[4])
return energie
Le principe est de chercher si "SCF Done"
est sur la ligne courante, puis de
la découper avec split
et d'enregistrer la bonne valeur.
Supposons que cette ligne, contenant l'énergie, apparaisse plusieurs fois dans le fichier, on peut construire une liste contenant toutes les valeurs en seulement deux lignes de code :
with open(fichier, "r") as f:
energies = [float(line.split()[4]) for line in f if "SCF Done:" in line]
Un cas plus complexe
On veut maintenant lire les valeurs de la section excitation energies
sur les
lignes 68 à 85. Par exemple, sur la ligne suivante, on cherche à lire
l'énergie, la longueur d'onde et la force d'oscillateur (f) :
Excited State 2: Singlet-A" 4.2831 eV 289.47 nm f=0.0000 <S**2>=0.000
Voici une proposition :
def read_td(fichier):
""" Lit la section excitation energies """
# les résultats seront dans une liste
transitions = list()
with open(fichier, "r") as f:
line = f.readline()
td = False
# lecture tant qu'on n'est pas à la fin du fichier
while line != "":
if "Excitation energies and oscillator strengths:" in line:
td = True
if td:
if "Excited State" in line:
val = line.split()
energie = float(val[4])
nm = float(val[6])
force = float(val[8].strip("f="))
transitions.append((energie, nm, force))
line = f.readline()
return transitions
transitions = read_td("soup.txt")
print(transitions)
Ce qui donnera :
[(3.9281, 315.64, 0.0054), (4.2831, 289.47, 0.0), (6.4162, 193.24, 0.0457), (7.949, 155.97, 0.0013)]
Mieux que split
les expressions régulières
Les expressions régulières permettent de réaliser avec peu de lignes des choses très complexes mais elles sont également difficiles à lire. Elles permettent d'identifier une chaîne de caractères suivant des critères précis. Nous allons reprendre l'exemple précédent.
Voici un outils en ligne très pratique pour tester vos expressions régulières : regex101
import re
def read_td(fichier):
""" Lit la section excitation energies """
# cette expression régulière repère tout type de nombre flottant
float_patt = re.compile("\s*([+-]?\d+\.\d+)")
transitions = list()
# read in file
with open(fichier, "r") as f:
line = f.readline()
td = False
# lecture tant qu'on n'est pas à la fin du fichier
while line != "":
if re.search("^Excitation energies and oscillator strengths:", line):
td = True
if td:
if re.search("^Excited State\s*\d", line):
val = [float(v) for v in float_patt.findall(line)]
transitions.append(tuple(val[0:3]))
line = f.readline()
return transitions
transitions = read_td("soup.txt")
print(transitions)
Commentaires :
- Il faut utiliser le module
re
pour regular expression re.search("regex", line)
est équivalent àif "regex" in line:
float_patt.findall(line)
renvoie toutes les valeurs qui correspondent au modèle défini parfloat_patt
"\s*([+-]?\d+\.\d+)"
nombre à virgule avec éventuellement un signe : +0.1 ou 3.14 ou 100. ou -27.21- Quelques éléments de syntaxe :
\d
pour digit\s
pour whitespace*
caractère précédent de 0 à un nombre de fois illimité+
caractère précédent de 0 à un nombre de fois illimité?
caractère précédent 0 ou 1 fois^
début de la ligne
Quelques exemples d'expressions régulières
Le fichier soup.txt
:
Standard basis: 6-31G(d,p) (5D, 7F)
There are 36 symmetry adapted cartesian basis functions of A' symmetry.
There are 13 symmetry adapted cartesian basis functions of A" symmetry.
There are 33 symmetry adapted basis functions of A' symmetry.
There are 13 symmetry adapted basis functions of A" symmetry.
46 basis functions, 108 primitive gaussians, 49 cartesian basis functions
16 alpha electrons 16 beta electrons
nuclear repulsion energy 106.6890740164 Hartrees.
NAtoms= 3 NActive= 3 NUniq= 3 SFac= 1.00D+00 NAtFMM= 60 NAOKFM=F Big=F
Integral buffers will be 131072 words long.
Regular integral format.
Two-electron integral symmetry is turned on.
One-electron integrals computed using PRISM.
NBasis= 46 RedAO= T EigKep= 3.97D-02 NBF= 33 13
NBsUse= 46 1.00D-06 EigRej= -1.00D+00 NBFU= 33 13
ExpMin= 1.17D-01 ExpMax= 2.19D+04 ExpMxC= 3.30D+03 IAcc=1 IRadAn= 1 AccDes= 0.00D+00
Harris functional with IExCor= 1009 and IRadAn= 1 diagonalized for initial guess.
HarFok: IExCor= 1009 AccDes= 0.00D+00 IRadAn= 1 IDoV= 1 UseB2=F ITyADJ=14
ICtDFT= 3500011 ScaDFX= 1.000000 1.000000 1.000000 1.000000
FoFCou: FMM=F IPFlag= 0 FMFlag= 100000 FMFlg1= 0
NFxFlg= 0 DoJE=T BraDBF=F KetDBF=T FulRan=T
wScrn= 0.000000 ICntrl= 500 IOpCl= 0 I1Cent= 200000004 NGrid= 0
NMat0= 1 NMatS0= 1 NMatT0= 0 NMatD0= 1 NMtDS0= 0 NMtDT0= 0
Petite list used in FoFCou.
Initial guess orbital symmetries:
Occupied (A') (A') (A') (A') (A') (A') (A") (A') (A') (A')
(A') (A') (A") (A") (A') (A')
Virtual (A") (A') (A') (A') (A") (A') (A') (A") (A') (A")
(A') (A') (A") (A') (A') (A") (A') (A') (A') (A')
(A") (A") (A') (A') (A') (A") (A") (A') (A') (A')
The electronic state of the initial guess is 1-A'.
Keep J ints in memory in symmetry-blocked form, NReq=1482832.
Requested convergence on RMS density matrix=1.00D-08 within 128 cycles.
Requested convergence on MAX density matrix=1.00D-06.
Requested convergence on energy=1.00D-06.
No special actions if energy rises.
Integral accuracy reduced to 1.0D-05 until final iterations.
Initial convergence to 1.0D-05 achieved. Increase integral accuracy.
SCF Done: E(RPBE-PBE) = -548.263942119 A.U. after 14 cycles
NFock= 14 Conv=0.63D-08 -V/T= 2.0030
ExpMin= 1.17D-01 ExpMax= 2.19D+04 ExpMxC= 3.30D+03 IAcc=3 IRadAn= 5 AccDes= 0.00D+00
HarFok: IExCor= 205 AccDes= 0.00D+00 IRadAn= 5 IDoV=-2 UseB2=F ITyADJ=14
ICtDFT= 12500011 ScaDFX= 1.000000 1.000000 1.000000 1.000000
Range of M.O.s used for correlation: 8 46
NBasis= 46 NAE= 16 NBE= 16 NFC= 7 NFV= 0
NROrb= 39 NOA= 9 NOB= 9 NVA= 30 NVB= 30
Keep J ints in memory in symmetry-blocked form, NReq=1810774.
Orbital symmetries:
Occupied (A') (A') (A') (A') (A') (A") (A') (A') (A') (A')
(A") (A') (A') (A") (A') (A')
Virtual (A") (A') (A') (A') (A") (A') (A') (A") (A") (A')
(A') (A') (A") (A') (A") (A') (A') (A') (A') (A')
(A") (A") (A') (A') (A') (A") (A") (A') (A') (A')
16 initial guesses have been made.
Convergence on wavefunction: 0.001000000000000
Iteration 1 Dimension 16 NMult 0 NNew 16
CISAX will form 16 AO SS matrices at one time.
Iteration 2 Dimension 32 NMult 16 NNew 16
Iteration 3 Dimension 36 NMult 32 NNew 4
Iteration 4 Dimension 39 NMult 36 NNew 3
Iteration 5 Dimension 40 NMult 39 NNew 1
***********************************************************************
Excited states from <AA,BB:AA,BB> singles matrix:
***********************************************************************
Ground to excited state transition densities written to RWF 633
Excitation energies and oscillator strengths:
Excited State 1: Singlet-A" 3.9281 eV 315.64 nm f=0.0054 <S**2>=0.000
16 -> 17 0.70680
This state for optimization and/or second-order correction.
Total Energy, E(TD-HF/TD-KS) = -548.119587803
Copying the excited state density for this state as the 1-particle RhoCI density.
Excited State 2: Singlet-A" 4.2831 eV 289.47 nm f=0.0000 <S**2>=0.000
15 -> 17 0.70716
Excited State 3: Singlet-A' 6.4162 eV 193.24 nm f=0.0457 <S**2>=0.000
14 -> 17 0.65477
15 -> 18 0.20991
16 -> 19 0.19021
Excited State 4: Singlet-A" 7.9490 eV 155.97 nm f=0.0013 <S**2>=0.000
13 -> 17 0.70470
SavETr: write IOETrn= 770 NScale= 10 NData= 16 NLR=1 NState= 4 LETran= 82.
Symmetry A' KE= 5.029717769773D+02
Symmetry A" KE= 4.367837409063D+01
1\1\GINC-DNAS-NODE33\SP\RPBEPBE TD-FC\6-31G(d,p)\O2S1\GVALLVER\22-Sep-
2015\0\\# PBEPBE/6-31G** 5d td=(nstates=4)\\SO2 molecule\\0,1\S,0,4.99
586601,4.99305474,5.\O,0,6.44958723,4.99309717,5.\O,0,4.28472976,6.260
9081,5.\\Version=EM64L-G09RevD.01\State=1-A'\HF=-548.2639421\RMSD=6.29
7e-09\PG=CS [SG(O2S1)]\\@
HEAVEN'S NET CASTS WIDE.
THOUGH ITS MESHES ARE COARSE, NOTHING SLIPS THROUGH.
-- LAO-TSU
Job cpu time: 0 days 0 hours 0 minutes 6.1 seconds.
File lengths (MBytes): RWF= 6 Int= 0 D2E= 0 Chk= 1 Scr= 1
Normal termination of Gaussian 09 at Tue Sep 22 21:55:11 2015.
Fin execution du job : mar. sept. 22 21:55:11 CEST 2015