¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Conceptos básicos de archivos y directorios
Definición de direcciones de archivo o directorio
Un archivo tiene habitualmente dos key properties: un nombre de archivo o filename, y un directorio o path donde se encuentra.
La estructura de archivos y directorios es diferente en distintos Sistemas Operativos, debemos conocer cómo se organiza en el que estamos trabajando.
Además, el símbolo para separar directorios y subdirectorios, también cambia entre Windows (\) y Linux o Mac (/).
Para que nuestro programa funcione en cualquier Sistema Operativo, podemos usar la función Path() de la biblioteca pathlib.
Path() devuelve un objeto de tipo Path, que al pasarlo a string, devolverá la cadena en función del Sistema Operativo en el que se esté ejecutando el programa. Al definir direcciones en el programa (usando Path), se usa / por convención, ya que entre los desarrolladores, suele ser linux el Sistema Operativo preferente.
from pathlib import Path myFiles = ['accounts.txt', 'details.csv', 'invite.docx'] for filename in myFiles: print(Path(r'C:/Users/Al', filename)) # Con Path() se pueden concatenar cadenas que definan el directorio. # C:\Users\Al\accounts.txt # C:\Users\Al\details.csv # C:\Users\Al\invite.docx
La biblioteca pathlib fue introducida en Python 3.4, reemplazando al viejo os.path de versiones anteriores.
Concatenar directorios con /
Del mismo modo que se pueden concatenar strings con el símbolo +, se pueden concatenar paths con el símbolo /.
from pathlib import Path homeFolder = Path('C:/Users/Al') subFolder = Path('spam') homeFolder / subFolder # WindowsPath('C:/Users/Al/spam') # Objeto tipo Path str(homeFolder / subFolder) # 'C:\\Users\\Al\\spam' # Hay dobles backlashes, ya que estamos en Windows y el primer \ es el carácter de escape
Sólo hay que tener en cuenta al unir paths con /, es que uno de los dos primeros valores que se pasan deben ser de tipo Path. Si son strings, por ejemplo, se produce un error TypeError.
El operador / reemplaza al viejo os.path.join() de versiones de Python anteriores.
Direcciones absolutas y relativas
Hay dos formas de especificar un directorio:
- Dirección absoluta: Comienza en el directorio raíz.
- Dirección relativa: Comienza en el directorio de trabajo.
Además se puede indicar:
- ./ Se indica “Este directorio” o directorio “en el que nos encontramos”, el directorio de trabajo.
- ../ Se indica el directorio “padre”
Directorio de trabajo y directorio de usuario
El directorio de trabajo es el directorio desde el que estamos trabajando, también denominado Current Working Directory o cwd.
- Comprobar diectorio de trabajo: Path.cwd().
- Cambiar el directorio de trabajo: os.chdir().
El directorio de usuario depende del Sistema Operativo, y es donde se guarda la información del usuario. Se recomienda usar este directorio para poner nuestros programas, ya que así nos aseguramos de tener todos los permisos necesarios.
Creación y manejo de directorios
Creación de directorios
Se pueden crear directorios, así como los directorios intermedios definifos si no existen, con la función os.makedirs(). Se pasa como argumento un string con la dirección completa.
También pueden crearse directorios con el método de Path, mkdir():
from pathlib import Path Path(r'C:\Users\Al\spam').mkdir() # mkdir() no crea directorios intermedios, para eso usar os.makedirs()
Trabajar con direcciones absolutas y relativas
El módulo (biblioteca) pathlib proporciona los siguientes métodos para comprobar si un path es absoluto o relativo:
- is_absolute() True si es absoluto.
- Path.cwd() / Path('my/relative/path') Creación de una dirección absoluta a partir de una relativa.
- Path.home() / Path('my/relative/path') Creación decuna dirección absoluta a partir de una relativa, tomando como base el diectorio de trabajo.
Otras funciones útiles:
- os.path.abspath(path) Retornará un string con el string absoluto de los argumentos.
- os.path.isabs(path) True si el argumentos es absoluto.
- os.path.relpath(path, start) Retornará una dirección relativa desde start hasta path. Si start no está indicada, tomará en su lugar el directorio de trabajo.
Partes de una dirección de archivo
Un objeto tipo Path se compone de diferentes partes, que constituyen sus atributos:
c:\Users\Al\spam.txt
- C: Drive Letra que denota la partición o dispositivo físico.
- C:\ Anchor Directorio raíz.
- \Users\Al\ Parent Directorio que contiene el archivo.
- spam.txt Name Archivo, formado a su vez:
- spam Stem Tallo, nombre del archivo sin la extensión.
- .txt Suffix Extensión, define el tipo de archivo.
Para obtener cada atributo, es tan fácil como indicarlo:
p = Path('C:/Users/Al/spam.txt') p.anchor # 'C:\\' p.parent # WindowsPath('C:/Users/Al') # parent es el único que es de tipo Path en lugar de string p.name # 'spam.txt' p.stem # 'spam' p.suffix # '.txt' p.drive # 'C:'
También se puede utilizar el módulo viejo os:
- os.path.dirname(path) Devuelve un string con todo lo que hay antes del último \ en el argumento.
- os.path.basename(path) Devuelve un string con todo lo que hay después del último \ en el argumento.
- os.path.split(path) Devuelve una tupla con dos elementos, correspondiente al dirname y al basename.
- os.sep Si se pasa como argumento del método split os.sep, devuelve cada elemento de la dirección como strings dentro de una lista:
calcFilePath = 'C:\\Windows\\System32\\calc.exe' calcFilePath.split(os.sep) # ['C:', 'Windows', 'System32', 'calc.exe']
Buscando tamaños de archivo y contenido de directorios
Se pueden buscar tamaños de archivo y contenido de directorios usando el módulo os:
- Obtener el tamaño en bytes de un archivo: os.path.getsize(path)
- Obtener una lista de los nombres de archivo de un directorio: os.listdir(path) Se puede usar en un bucle for en lugar de range() para recorrer los archivos de un directorio.
También se pueden usar patrones Glob para obtener archivos de un directorio. Los patrones Glob pueden realizar búsquedas de forma similar a la de las expresiones regulares, aunque es más sencillo:
p = Path('C:/Users/Al/Desktop') p.glob('*') # <generator object Path.glob at 0x000002A6E389DED0> Devuelve un objeto generador list(p.glob('*')) # Crea una lista de los archivos que se encuentran en el directorio definido en p, en formato absoluto
como argumentos de glob() se especifica el patrón de forma similar a una expresión regular:
- Será tomado en consideración cualqueir texto que se indique.
- '*' Uno o varios caracteres, cualesquiera. Ejemplo: glob('*.txt') buscaría todos los archivos de texto.
- '?' Unúnico carácter cualquiera.
- Se pueden mezclar para obtener patrones más complejos.
Validación de paths
Muchas funciones dan un error si la dirección indicada no funciona. Algunos métodos útiles de tipos de objeto Path, son (asumiendo p como objeto tipo Path):
- p.exists() True si la dirección existe.
- p.is_file() True si la dirección existe y es un archivo.
- p.is_dir() True si la dirección existe y es un directorio.
Para estos mismos cometidos podrían usarse los viejos métodos os.path.exists(path), os.path.isfile(path), y os.path.isdir(path).
Proceso de lectura/escritura de archivos
En este apartado se verá la forma de leer y escribir en archivos de texto plano.
Lectura/escritura básica
Los métodos de la clase pathlib más sencillos y directos para leer/escribir con archivos son path.read_text() y path.write_text(string).
- path.read_text() devuelve un string con el contenido completo del archivo de texto.
- path.write_text(string) devuelve el número de caracteres escritos, crea un nuevo archivo, si no existe, y si existe, lo sobreescribe, ojo con esto.
Lectura/escritura con open()
Proceso a seguir:
- Se llama a la función open(), que devuelve un objeto de tipo File: archivo = open(dirección del archivo)
- Se llama a los métodos read() o write() del objeto File.
- Se cierra el archivo con el método close() del objeto File.
Lectura
La función open() permite un segundo argumento en el que se indica el modo en el que se abre el archivo, por defecto en modo lectura (argumento: 'r').
El método read() devuelve en un único string el contenido de todo el archivo. Con el método readlines() se obtiene una lista en la que cada elemento es el string correspondiente a cada línea del archivo (cada string termina con \n, salvo el último, lógicamente).
Escritura
Para escribir texto en un archivo de texto plano, éste debe de abrirse con open() indicando el modo:
- 'w': Si no existe en archivo, se crea. Comienza a escribir desde el inicio del documento y si hay algo ya escrito, se sobreescribe.
- 'a': Si no existe en archivo, se crea. Comienza a escribir desde el final del documento.
En ambos casos, siempre se escribe la cadena que se pasa como argumento del método write(). Devuelve el número de caracteres escritos.
Guardar variables
Guardar variables en archivos binarios
Con el módulo shelve se pueden guardar variables en un archivo binario, para después recuperar sus valores. De ese modo, no se pierde informaión al cerrar el programa (las variables normales son destruidas).
La forma de usar esta funcionalidad es similar a la de leer/escribir en un archivo:
- Importamos la biblioteca: import shelve
- Damos un nombre a los archivos binarios que se crearán ('mydata'), los abrimos (con shelve se permite tanto leer como escribir) y asignamos el valor devuelto a una variable: shelfFile = shelve.open('mydata')
- Trabajamos con la información que contiene:
- Para escribir (guardar) información, se guarda como se haría en un diccionario.
- Para leer (recuperar) información, también se hace como en un diccionario: atendiendo a la clave entre corchetes.
- Es posible listar la información con la función list()
- Cerramos el binario con close(): ShelfFile.close()
import shelve shelfFile = shelve.open('mydata') cats = ['Zophie', 'Pooka', 'Simon'] shelfFile['cats'] = cats shelfFile['cats'] # ['Zophie', 'Pooka', 'Simon'] list(shelfFile.keys()) # ['cats'] list(shelfFile.values()) # [['Zophie', 'Pooka', 'Simon']] shelfFile.close()
Función pprint.pformat()
En este caso la idea es guardar las variables en un archivo de python (.py), de forma que pueda importarse como una biblioteca, y de ese modo recuperar los dartos.
Para ello se utiliza el método pformat() de la biblioteca pprint (Pretty Print), que devuelve una variable tal y cmo se escribe en código.
import pprint cats = [{'name': 'Zophie', 'desc': 'chubby'}, {'name': 'Pooka', 'desc': 'fluffy'}] pprint.pformat(cats) # "[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]" fileObj = open('myCats.py', 'w') fileObj.write('cats = ' + pprint.pformat(cats) + '\n') # 83 fileObj.close()
import myCats myCats.cats # [{'name': 'Zophie', 'desc': 'chubby'}, {'name': 'Pooka', 'desc': 'fluffy'}] myCats.cats[0] # {'name': 'Zophie', 'desc': 'chubby'} myCats.cats[0]['name'] # 'Zophie'
Con esta funcionalidad los datos se guardan en texto plano, fácil de editar por cualquiera.
De este modo se pueden guardar variables de tipos básicos (string, enteros, listas, diccionarios, etc), pero no de tipos más complejos (como Files).
Para guardar datos más complejos es necesario usar el módulo shelve.
