Pour manipuler aisément les fichiers il faut avoir abordé 3 notions:
Pour lire et écrire du texte dans les fichiers, il faut spécifier correctement l'encodage. L'objet fichier est créé avec la fonction built-in open(), il se chargera d'encoder/décoder les caractères en fonction de l'encodage choisit:
file = open('/path/to/file.txt', 'w', encoding='utf8') for cpt in range(100): file.write(f"ligne {cpt:4d}\n") # l'appel de la méthode close() est important file.close()
En python les fichiers sont des itérateur: ils peuvent être directement intégrés à une boucle for:
file = open('/path/to/file.txt', 'r', encoding='utf8') for line in file: # le fichier est parcouru ligne par ligne # transformer la str en liste line = line.split() # la liste étant mutable on peut effectuer nos traitements ... file.close()
Le code précédent ne garantit pas que la ressource fichier soit bien libérée: exception à l’exécution ou oubli d'appel pas la méthode close(). Le protocole de context manager assurer l'ensemble des opérations de libération des ressources auprès du système d'exploitation lorsque un objet python n'est plus utilisé. L'objet fichier implémente ce protocole, pour l'utiliser il faut le placer après l'instruction with:
with open('/path/to/filename.txt') as file: # bloc d'instruction lié au context manager for line in file: print line
with open('/path/to/filename.txt', 'bw') as file: # bloc d'instruction lié au context manager for line in range(100): file.write(b'\xff') # l'objet doit être de type bytes, pour convertir un int # c = 0xff.to_bytes(1,byteorder='little',signed=False)
Pour vérifier le contenu du fichier, on peut utiliser od:
#affiche le flux par valeurs hexadécimales de 1 octet interprétation des valeurs # en little endian od --address-radix=d --width=10 --output-duplicates --format=x1 --endian=little /tmp/test.raw 0000000 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 0000010 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 0000020 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 0000030 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 0000040 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 0000050 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 0000060
Les modes les plus utilisés:
Mode | Description |
---|---|
“r” | read, lecture |
“w” | write, écriture. Si un contenu existait il est écrasé. |
“a” | append, ajout. Ecriture en fin de fichier. Conserve le contenu préexistant |
Le détail des modes d'ouvertures existant est intégré à la documentation de la fonction built-in open().
La méthode read() permet de lire dans un fichier un buffer d'une taille choisit. Si la taille du buffer n'est pas spécifiée, c'est tout le fichier qui est retourné.
with open('/path/to/filename.txt', 'bw') as file: # bloc d'instruction lié au context manager all_content = file.read() print(f"contenu complet:\n {all_content}", end="")
with open('/path/to/filename.txt', 'bw') as file: # bloc d'instruction lié au context manager for bloc in range(10): #lecture par bloc de 4 caractères print(f"bloc ID {bloc}: {repr(file.read(4))}")
Pour des raisons de performances, le système d'exploitation peut différer les demandes de lectures/écritures en plaçant les données dans des tampons. Dans certains cas ce comportement par défaut peut être génant: la méthode flush() permet de vider les tampons et forcer immédiatement la lecture/écriture.
Pour opérer sur les chemins, nom de fichiers présents sur l'arborescence du système d'exploitation il y avait les module os et glob aujourd'hui dépréciés.
On utilisera plutôt pathlib:
filename = '/tmp/test.txt' from pathlib import Path path = Path(filename) # retourne True si le fichier existe path.exists() # retourner un tuple contenant entre autre propriétaire, taille, date d'accès path.stat() file_size = path.stat().st_size() # Détruire un fichier: path.unlink() # rechercher des fichiers dirpath = Path('./data/') for files in dirpath.glob("*.txt"): print(file)
Lors de l'execution d'un programme python les données en mémoire ont une représentation qui dépend de l'architecture machine. Cette forme bien adaptée pour le traitement et les calcul sur l'hote n'est pas forcement pertinante lorsqu'il sagit de stocker ou transmettre l'information. Il convient donc de faire de la traduction dans les deux sens entre d'une part la représentation en mémoire et d'autre part la représentation sur le réseau ou les disques de stockage. Pour cela on utilise divers encodages (marshalling) comme JSON1) ou CSV 2)
JSON s'est popularisé car il est léger, permet de communiquer avec des applications web en JavaScript et qu'il est supporté par de nombreux langage. Il permet de sérialiser facilement la plupart des types de base:
dataset = [10,33, 'ma chaine', [2.5,3.1], {'nom':'Doe', 'prenom':'John', 'age':33}, # les tuples seront convertis en listes (2,3,4) ] # Ecrire dans un fichier au format JSON with open("/tmp/test.json", 'w', encoding='utf8') as fs_json: json.dump(dataset, fs_json) del(dataset) # Relire, récupérer des données au format JSON with open("/tmp/test.json", 'r', encoding='utf-8') as json_input: dataset = json.load(json_input) dataset [10, 33, 'ma chaine', [2.5, 3.1], {'nom': 'Doe', 'prenom': 'John', 'age': 33}, [2, 3, 4]]
Le module pickle offre un format proche de JSON intégrant les types de base et permettant de faire des sauvegardes locales d'objets. Pour enregistrer facilement des objets Python il peut être très utile.
Les fichiers d'entrées/sorties standards sont exposés par Python via le module sys
import sys for channel in (sys.stdin, sys.stdout, sys.stderr): print(channel, f" at @{id(channel):0x}")
Comme sys.stdout est une variable du module sys référençant un objet fichiere, on peut lui faire référencer un autre fichier et rediriger ainsi les sorties.