Skip to article frontmatterSkip to article content

formats et librairies

si vous devez lire des formats communs, faites-le avec:

mais sinon: open() est le point d’entrée

utilisez toujours un with

# on n'a pas encore étudié l'instruction with
# mais je vous conseille de toujours procéder comme ceci

# avec with on n'a pas besoin de fermer le fichier
with open('temporaire.txt', 'w') as writer:
    for i in 10, 20, 30:
        print(f"{i} {i**2}", file=writer)

avantage du with:

lecture avec for

# pour inspecter ce qu'on vient d'écrire
# dans le fichier qui s'appelle "temporaire.txt"
# dans le répertoire courant

# lire un fichier texte ligne par ligne
# on ne peut pas faire plus compact et lisible !

# remarquez aussi:
# open() sans le mode ⇔ open('r')

with open("temporaire.txt") as reader:
    for line in reader:
        # attention ici line contient déjà le newline
        # c'est pourquoi on demande à print() de ne pas
        # en ajouter un second
        print(line, end="")
10 100
20 400
30 900

autres méthodes en lecture

comme toujours, il y a plein d’autres méthodes disponibles sur les fichiers texte, reportez-vous à la documentation pour des besoins spécifiques

fichiers ouverts en binaire

ajouter b dans le mode

tous les fichiers ne sont pas des fichiers texte
par ex. un exécutable, un fichier dans un format propriétaire

pour ouvrir un fichier en mode binaire:

# pour fabriquer un objet bytes, je peux par exemple 
# encoder un texte qui comporte des accents
# (on reparlera des encodages plus tard)

text = "noël en été\n"
binaire = text.encode(encoding="utf-8")

binaire
b'no\xc3\xabl en \xc3\xa9t\xc3\xa9\n'
# j'ai bien un objet bytes, 
# et sa taille correspond au nombre d'octets 
# et non pas au nombre de caractères

type(binaire), len(binaire), len(text)
(bytes, 15, 12)
# remarquez le 'b' dans le mode d'ouverture

with open('temporaire.bin', 'wb') as out_file:
    # je peux du coup écrire un objet bytes
    out_file.write(binaire)
# pareil en lecture, le mode avec un 'b'
# va faire que read() retourne un objet bytes

with open('temporaire.bin', 'rb') as in_file:
    binaire2 = in_file.read()
# et donc on retombe bien sur nos pieds
binaire2 == binaire
True
# ça aurait été pareil 
# si on avait ouvert le fichier en mode texte
# puisque ce qu'on a écrit dans le fichier binaire,
# c'est justement l'encodage en utf-8 d'un texte

#             sans le b ici ↓↓↓
with open('temporaire.bin', 'r') as feed:
    text2 = feed.read()
    
text2 == text
True

le module pathlib

objectifs

présentation du module

un exemple

# savoir si un chemin correspond à un dossier
from pathlib import Path

tmp = Path("temporaire.txt")

if tmp.is_file():
    print("c'est un fichier")
c'est un fichier
# donc on peut l'ouvrir

with tmp.open() as feed:
    for line in feed:
        print(line, end="")
10 100
20 400
30 900
# on peut faire des calculs sur les noms de fichier
tmp.suffix
'.txt'
# changer de suffixe
tmp.with_suffix(".py")
PosixPath('temporaire.py')
# calculer le chemin absolu
# le couper en morceaux, etc...
tmp.absolute().parts
('/', 'home', 'runner', 'work', 'slides', 'slides', 'notebooks', 'temporaire.txt')

construire un objet Path

# un chemin absolu
prefix = Path("/etc")

# le chemin absolu du directory courant
dot = Path.cwd()

# ou du homedir
home = Path.home()

# un nom de ficher
filename = Path("apache")
# par exemple le répertoire courant est

dot
PosixPath('/home/runner/work/slides/slides/notebooks')

l’opérateur /

un exemple intéressant de surcharge d’opérateur: selon le type de ses opérandes, / fait .. ce qu’il faut ! par exemple ici on ne fait pas une division !

# Path / Path -> Path bien sûr
type(prefix / filename)
pathlib.PosixPath
# Path / str -> Path
type(prefix / "apache2")
pathlib.PosixPath
# str / Path -> Path
type("/etc" / Path("apache2"))
pathlib.PosixPath
# mais bien sûr str / str -> TypeError
try:
    "/etc" / "apache2"
except Exception as e:
    print("OOPS", e)
OOPS unsupported operand type(s) for /: 'str' and 'str'

calculs sur les chemins

j’ai créé un petite hiérarchie de fichiers dans le dossier filepath-globbing qui ressemble à ceci

# pour commencer, voilà comment on peut trouver son chemin absolu

globbing = Path("filepath-globbing")
absolute = globbing.absolute()
absolute
PosixPath('/home/runner/work/slides/slides/notebooks/filepath-globbing')
# si on a besoin d'un str, comme toujours il suffit de faire

str(absolute)
'/home/runner/work/slides/slides/notebooks/filepath-globbing'
# les différents morceaux de ce chemin absolu

absolute.parts
('/', 'home', 'runner', 'work', 'slides', 'slides', 'notebooks', 'filepath-globbing')
# juste le nom du fichier, sans le chemin

absolute.name
'filepath-globbing'
# le chemin, sans le nom du fichier

absolute.parent
PosixPath('/home/runner/work/slides/slides/notebooks')
# tous les dossiers parent

list(absolute.parents)
[PosixPath('/home/runner/work/slides/slides/notebooks'), PosixPath('/home/runner/work/slides/slides'), PosixPath('/home/runner/work/slides'), PosixPath('/home/runner/work'), PosixPath('/home/runner'), PosixPath('/home'), PosixPath('/')]

pattern-matching

# est-ce que le nom de mon objet Path 
# a une certaine forme ?

absolute.match("**/notebooks/*")
True
absolute.match("**/*globbing*")
True

pattern-matching - dans un dossier

# à présent c'est plus intéressant
# avec des chemins relatifs
root = Path("filepath-globbing")

# tous les fichiers / répertoires 
# qui sont immédiatement dans le dossier
list(root.glob("*"))
[PosixPath('filepath-globbing/a1'), PosixPath('filepath-globbing/c'), PosixPath('filepath-globbing/b')]
# les fichiers/dossiers immédiatement dans le dossier
# et dont le nom se termine par un chiffre
list(root.glob("*[0-9]"))
[PosixPath('filepath-globbing/a1')]

pattern-matching - dans tout l’arbre

# ce dossier, et les dossiers en dessous
# à n'importe quel étage

list(root.glob("**"))
[PosixPath('filepath-globbing'), PosixPath('filepath-globbing/c'), PosixPath('filepath-globbing/b'), PosixPath('filepath-globbing/c/cc')]
# tous les fichiers/dossiers 
# dont le nom termine par un chiffre

list(root.glob("**/*[0-9]"))
[PosixPath('filepath-globbing/a1'), PosixPath('filepath-globbing/b/b2'), PosixPath('filepath-globbing/c/cc/c2')]

notions avancées

encodages par défaut

import locale
locale.getpreferredencoding(False)
'UTF-8'
with open('temporaire.txt', 'r', encoding='utf8') as in_file:
    print(in_file.read())
10 100
20 400
30 900

fichiers système

import sys
sys.stdout
<ipykernel.iostream.OutStream at 0x7fb898947f40>