SUPERCAT.DEV

Benvenut* sul mio blog

PYTHON

Richiami di Python: i file

07-11-2022

Leggere, scrivere file

GESTIONE FILE IN PYTHON

I file differiscono tra:

  • text files (caratteri unicode)
  • binary files (dati raw non interpretati)

PATHLIB

Fa parte della libreria standard

from pathlib import Path 

path = Path("dir1", "dir2", "myfile.txt") # /dir1/dir2/myfile.txt
f = open(path)

home = Path.home()
path = Path(home, "dir1", "dir2", "myfile.txt") # percorso completo /home/emilie/dir1/dir2/myfile.txt
f = open(path)

APERTURA FILE

Per aprire un file file_object = open(filename, mode)
Se c'è un errore viene sollevata un FileNotFoundError
All'apertura viene creato un file pointer collegato poi con un offset (dal file pointer)
Sempre chiudere un file quando abbiamo finito con file_object.close()

f = open("myfile.txt")
print(f.encoding)		# UTF-8
f.close()

Per evitare di dimenticarsi di chiudere il file meglio usare un context manager come with

with open("myfile.txt", "rt") as f:
	testo = f.read(10) 	# Se voglio leggere solo 10 byte
	print(testo)		# Se scrivevo solo f.read() avevo tutto il contenuto del testo

Readline() legge fino a quando trova un carattere EOL (end of line) -> \n

with open("myfile.txt", "rt") as f:
	linea = f.readline()	# mi legge solo la prima linea
	print(linea)

Visto che mi crea un iteratore posso fare così per leggere tutte le linee

with open("myfile.txt", "rt") as f:
	c = 0
	for linea in f:
		c += 1
		print(f"{c}: {linea}")

Se invece voglio che mi restituisca una lista con tutte le linee

with open("myfile.txt", "rt") as f:
	linee = f.readlines()
	for linea in linee:
		print(f"{linea}")

MODE

Abbiamo queste possibilità:

  • r: apertura in lettura
  • w: per scrittura (se il file esiste già viene sovrascritto)
  • x: per la creazione (se esiste già l'operazione fallisce)
  • a: per fare un append alla fine del file (se il file non esiste lo crea)
  • t: modo testo
  • b: modo binario
  • +: apre un file per modificarlo (lettura e scrittura)

Per cui possiamo avere "r+", "rb+", "w", ecc.

Esempio

f = open("path_to_file", mode = 'r', encoding='utf-8')

Come parametri ci sono anche:

  • buffering (opz): buffering policy
  • encoding (opz): formato
  • errors (opz): come gestire gli errori
  • newline (opz): come gestire le nuove linee (valori possibili: None, ' ', '\n', '\r', '\r\n')

Esempio di lettura file di testo

with open("myfile.txt", "rt") as f:
	testo = f.read()
	print(testo)

BYTES E BYTEARRAY

bytes (sequenza immutabili di byte) bytearray (sequenza mutabile di byte)

b = b'supercat'

print(type(b))	# <class 'bytes'>
print(b)	# b'supercat'
ba = bytearray('supercat', 'utf-8')
ba.extend(b'.dev')

print(type(ba))	# <class 'bytearray'>
print(ba)	# bytearray(b'supercat.dev')

ENCODE / DECODE

Encode per codificare oggetti text (in un oggetto bytes)
Decode per decodificare oggetti in bytes (in una stringa)

s = 'supercat'
sb = s.encode('utf-8')
print(type(sb))		# <class 'bytes'>

b = b'supercat'
st = b.decode('utf-8')
print(type(st))		# <class 'str'>

WRITE

Può essere usato su qualunque oggetto che ha un puntatore a file
Posso usare anche due open in with

with open("in.txt", "rt") as f, open("out.txt", "wt") as o:
    testo = f.read()
    o.write(testo)

SPOSTARSI NEI FILE CON TELL E SEEK

Quando apriamo un file in lettura il File Pointer è all'inizio, se invece lo apriamo in accodamento ('a') il File Pointer è alla fine del file
Tell ci restituisce il valore dell'offset
Seek posiziona l'offset nella posizione richiesta. Seek ha anche un secondo parametro (whence) opzionale che può assumere tre valori:

  • os.SEEK_SET: (0) inizio file
  • os.SEEK_CUR: (1) posizione corrente
  • os.SEEK_END: (2) fine del file (per cui offset conta all'indietro) f.seek(-2, os.SEEK_END)

Se vogliamo usare i SEEK_XXX dobbiamo usare import os

with open("in.txt", "rt") as f:
	offset = f.tell() 	# ritorna l'offset corrente, inizio 0
	f.seek(offset) 		# imposta il puntatore su questo valore

Legge un file di testo saltando i primi 3 byte e leggendo i successivi 3

with open("myfile.txt", "rt") as f:
    offset = f.tell()
    offset += 3
    f.seek(offset)
    testo = f.read(4)	# legge 3 byte
    print(testo)	# bbb

Se voglio leggere gli ultimi 4 caratteri del file compreso EOL

import os
with open("myfile.txt", "rb") as f:
    f.seek(-4, os.SEEK_END)
    testo = f.read()	
    print(testo)	# b'\nefg'