Python 3 per a no programadors/Entrada-Sortida amb fitxers


Aquí hi ha un exemple senzill d'entrada/sortida (I/O) des de o cap a un fitxer:

# Escriure un fitxer
fitxer_sortida = open("prova.txt", "wt")
fitxer_sortida.write("Aquest text va cap a un fitxer extern\nMireu-lo i ho veureu!")
fitxer_sortida.close()

# Llegir un fitxer
fitxer_entrada = open("prova.txt", "rt")
text = fitxer_entrada.read()
fitxer_entrada.close()

print(text)

La sortida i els continguts del fitxer prova.txt són:

Aquest text va cap a un fitxer extern
Mireu-lo i ho veureu!

Fixeu-vos que ha escrit un fitxer anomenat prova.txt al directori des d'on heu executat el programa. El \n a la cadena de caràcters indica al llenguatge Python que cal posar un salt de línia (new line) al lloc on hi ha el \n.

Una visió de conjunt del procés d'Entrada/sortida és:

  • Obtenir un objecte de tipus fitxer amb la funció open.
  • Llegir o escriure a l'objecte de tipus fitxer (depenent de com s'ha obert)
  • Tancar-lo

El primer pas és obtenir un objecte fitxer. La manera de fer-ho és fent servir la funció open. El seu format és objecte_fitxer = open(nom_del_fitxer, mode) on objecte_fitxer és el nom de la variable on s'emmagatzemarà l'objecte de tipus fitxer, nom_del_fitxer és una cadena amb el nom del fitxer, i mode és "rt" per llegir (read) el fitxer com a text o bé "wt" per a escriure (write) el fitxer com a text (i uns quants més que ara ens saltarem). Tot seguit es poden invocar les funcions de l'objecte fitxer. Les dues funcions més frequents són: read (llegir) i write (escriure). La funció write afegeix una cadena al final de fitxer. La funció read llegeix el següent que troba al fitxer i ho retorna com una cadena. Si no se li dóna cap argument retornarà el fitxer sencer (tal com s'ha fet a l'exemple).

Tot seguit hi ha una nova versió del programa dels nombres de telèfon que s'ha fet a capítols anteriors:


def imprimeix_numeros(numeros):
    print(u"Números de Telèfon:")
    for k, v in números.items():
        print("Nom:", k, u"\tNúmero:", v)
    print()

def afegir_numero(numeros, nom, numero):
    numeros[nom] = numero

def cercar_numero(numeros, nom):
    if nom in numeros:
        return u"El número és " + numeros[nom]
    else:
        return "no s'ha trobat " + nom

def treure_numero(numeros, nom):
    if nom in numeros:
        del numeros[nom]
    else:
        print("no s'ha trobat ", nom)

def carrega_numeros(numeros, nom_del_fitxer):
    fitxer_entrada = open(nom_del_fitxer, "rt")
    while True:
        linia_entrada = fitxer_entrada.readline()
        if not linia_entrada:
            break
        linia_entrada = linia_entrada[:-1]
        nom, numero = linia_entrada.split(",")
        numeros[nom] = numero
    fitxer_entrada.close()

def grava_numeros(numeros, nom_del_fitxer):
    fitxer_sortida = open(nom_del_fitxer, "wt")
    for k, v in numeros.items():
        fitxer_sortida.write(k + "," + v + "\n")
    fitxer_sortida.close()

def imprimeix_menu():
    print(u'1. Imprimir Números de Telèfon')
    print(u'2. Afegir-hi un Número de Telèfon')
    print(u'3. El·liminar-hi un Número de Telèfon')
    print(u'4. Cercer un Número de Telèfon')
    print(u'5. Carregar números')
    print(u'6. Gravar números')
    print(u'7. Sortir')
    print()

llista_de_numeros = {}
tria_menu = 0
imprimeix_menu()
while True:
    tria_menu  = int(input("Escriviu un nombre (1-7): "))
    if tria_menu  == 1:
        imprimeix_numeros(llista_de_numeros)
    elif tria_menu  == 2:
        print(u"Afegir Nom i Número")
        nom = input("Nom: ")
        telefon = input(u"Número: ")
        afegir_numero(llista_de_numeros, nom, telefon)
    elif tria_menu  == 3:
        print(u"El·limnar Nom i Número")
        nom = input("Nom: ")
        treure_numero(llista_de_numeros, nom)
    elif tria_menu  == 4:
        print(u"Cercar Númro")
        nom = input("Nom: ")
        print(cercar_numero(llista_de_numeros, nom))
    elif tria_menu  == 5:
        nom_del fitxer = input("Nom del Fitxer a carregar: ")
        carrega_numeros(llista_de_numeros, filename)
    elif tria_menu  == 6:
        nom_del fitxer = input("Nom del fitxer on gravar-los: ")
        save_numbers(llista_de_numeros, nom_del fitxer)
    elif tria_menu  == 7:
        break
    else:
        imprimeix_menu()

print("Passi-ho bé")

Fixeu-vos que inclou gravar i carregar fitxers. Aquí hi ha alguns resultats d'executar-lo dues vegades:

1. Imprimir Números de Telèfon
2. Afegir-hi un Número de Telèfon
3. Eliminar-hi un Número de Telèfon
4. Cercer un Número de Telèfon
5. Carregar números
6. Gravar números
7. Sortir
Escriviu un nombre (1-7): 2
Afegir Nom i Número
Nom: Jill
Número: 1234
Escriviu un nombre (1-7): 2
Afegir Nom i Número
Nom: Fred
Número: 4321
Escriviu un nombre (1-7): 1
Números de Telèfon:
Nom: Jill     Número: 1234
Nom: Fred     Número: 4321

Escriviu un nombre (1-7): 6
Nom del fitxer on gravar-los: nombres.txt

Escriviu un nombre (1-7): 7
Passi-ho bé
1. Imprimir Números de Telèfon
2. Afegir-hi un Número de Telèfon
3. Eliminar-hi un Número de Telèfon
4. Cercer un Número de Telèfon
5. Carregar números
6. Gravar números
7. Sortir

Escriviu un nombre (1-7): 5
Nom del Fitxer a carregar: nombres.txt

Escriviu un nombre (1-7): 1
Números de Telèfon:
Nom: Jill     Número: 1234
Nom: Fred     Número: 4321

Escriviu un nombre (1-7): 7
Passi-ho bé

Els bocins nous d'aquest programa són:

def carrega_numeros(numeros, nom_del_fitxer):
    fitxer_entrada = open(nom_del_fitxer, "rt")
    while True:
        linia_entrada = fitxer_entrada.readline()
        if not linia_entrada:
            break
        linia_entrada = linia_entrada[:-1]
        nom, numero = linia_entrada.split(",")
        numeros[nom] = numero
    fitxer_entrada.close()

def grava_numeros(numeros, nom_del_fitxer):
    fitxer_sortida = open(nom_del_fitxer, "wt")
    for k, v in numeros.items():
        fitxer_sortida.write(k + "," + v + "\n")
    fitxer_sortida.close()

Primer observeu la part de gravar del programa. Primer crea un objecte de tipus fitxer amb la instrucció open(nom_de_fitxer, "wt"). Tot segui crea una línia per a cada número de telèfon amb la instrucció fitxer_sortida.write(x + "," + numeros[x] + "\n"). Això escriu una línia que conté el nom, una coma, el número i tot seguit un salt de línia.

La part de càrrega és una mica més complicada. Comença per obtenir un objecte de tipus fitxer. Llavors fa servir un bucle while True: per anar repetint el procés fins que es trobi una instrucció break. Llavors obté una línia amb la instrucció linia_entrada = fitxer_entrada.readline(). la funció readline retorna una cadena buida quan s'arriba a un final de fitxer. La instrucció if ho vigila i quan això passa surt del bucle while executant una instrucció break. Esclar, si la funció readline no retornés una codi newline al final de cada línia no hi hauria manera de saber si una cadena buida és una línia buida o el final del fitxer per tant es deixa el codi newline en el que retorna la instrucció readline. Per tant cal eliminar-lo. La línia linia_entrada = linia_entrada[:-1] fa precisament això a base de descartar l'últim caràcter. Llavors la línia nom, numero = linia_entrada.split(",") parteix la línia al lloc on hi ha la coma en un nom i un número. Llavors això s'afegeix al diccionari numeros.