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.
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.
Hay dos formas de especificar un directorio:
Además se puede indicar:
El directorio de trabajo es el directorio desde el que estamos trabajando, también denominado Current Working Directory o cwd.
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.
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()
El módulo (biblioteca) pathlib proporciona los siguientes métodos para comprobar si un path es absoluto o relativo:
Otras funciones útiles:
Un objeto tipo Path se compone de diferentes partes, que constituyen sus atributos:
c:\Users\Al\spam.txt
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:
calcFilePath = 'C:\\Windows\\System32\\calc.exe' calcFilePath.split(os.sep) # ['C:', 'Windows', 'System32', 'calc.exe']
Se pueden buscar tamaños de archivo y contenido de directorios usando el módulo os:
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:
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):
Para estos mismos cometidos podrían usarse los viejos métodos os.path.exists(path), os.path.isfile(path), y os.path.isdir(path).
En este apartado se verá la forma de leer y escribir en archivos de texto plano.
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).
Proceso a seguir:
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).
Para escribir texto en un archivo de texto plano, éste debe de abrirse con open() indicando el modo:
En ambos casos, siempre se escribe la cadena que se pasa como argumento del método write(). Devuelve el número de caracteres escritos.
Con el fin de tener un código más limpio, es común a la hora de trabajar con directorios usar la sentencia with, que nos permite evitar tener que estar cerrando el archivo con 'close()'.
Un ejemplo:
with open('file_path', 'w') as file: file.write('hello world !')
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:
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()
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.
Para realizar acciones sobre archivos y directorios, como mover, copiar, renombrar o borrar, vamos a utilizar la biblioteca shutil shell utilities.
Para copiar un único archivo se utiliza el método shutil.copy(source, destination).
Para copiar un directorio completo, con todos sus subdirectorios y archivos, se utiliza del mismo modo la función shutil.copytree(source, destination). Devuelve un dato Path con el dirección del directorio copiado.
Para mover un archivo o un directorio, se utiliza el método shutil.move(source, destination):
import os from pathlib import Path for filename in Path.home().glob('*.rxt'): #os.unlink(filename) # Para ver los próximos archivos a eliminar, se comenta esta línea. Si estamos seguros, entonces se descomenta. print(filename)
La idea es enviar los archivos a la papelera de reciclaje, en lugar de borrarlos directamente.
Para ellos usamos el método send2trash() del módulo send2trash.
Es un módulo de terceros que debe instalarse con pip install –user send2trash.
>>> import send2trash >>> baconFile = open('bacon.txt', 'a') # creates the file >>> baconFile.write('Bacon is not a vegetable.') 25 >>> baconFile.close() >>> send2trash.send2trash('bacon.txt')
La biblioteca os nos proporciona la función os.walk(string), que usada en conjunto con un bucle for (en lugar de range()), en cada iteración se mueve por los directorios del árbol, lo que permite recorrer el arbol de directorios:
En cada iteración del bucle for, la función walk() devuelve:
''' C:/ delicius cats catnames.txt zophie.jpg walnut waffles butter.txt spam.txt ''' import os for folderName, subfolders, filenames in os.walk('C:\\delicious'): print('The current folder is ' + folderName) for subfolder in subfolders: print('SUBFOLDER OF ' + folderName + ': ' + subfolder) for filename in filenames: print('FILE INSIDE ' + folderName + ': '+ filename) print('')
The current folder is C:\delicious SUBFOLDER OF C:\delicious: cats SUBFOLDER OF C:\delicious: walnut FILE INSIDE C:\delicious: spam.txt The current folder is C:\delicious\cats FILE INSIDE C:\delicious\cats: catnames.txt FILE INSIDE C:\delicious\cats: zophie.jpg The current folder is C:\delicious\walnut SUBFOLDER OF C:\delicious\walnut: waffles The current folder is C:\delicious\walnut\waffles FILE INSIDE C:\delicious\walnut\waffles: butter.txt
Para trabajar con archivos comprimidos en ZIP, (extensión .zip) usaremo el módulo zipfile.
La forma de trabajar es muy similar, asignando a tipos de datos ZipFile (similares a Path) el archivo comprimido con el que trabajaremos para gestionar sus datos.
Para leer archivos comprimidos en ZIP:
exampleZip = zipfile.ZipFile(Path.wcd()/'ham'/'meat.zip')
exampleZip.namelist()
spamInfo = exampleZip.getinfo('spam.txt') spamInfo.file_size spamInfo.compress_size
exampleZip.close()
Para extraer todo el contenido de un ZIP, se utiliza el método extractall(), al que se le puede pasar un argumento string en el que se define la dirección en la que se desea extraer. Si no, se extraerá en el directorio raíz.
import zipfile, os from pathlib import Path p = Path.home() exampleZip = zipfile.ZipFile(p / 'example.zip') exampleZip.extractall() # exampleZip.extractall('C:\\delicious') # Para extraerlo en una diección concreta. exampleZip.close()
Para extraer un archivo concreto se usa el método extract(), en la que el primer argumento es el archivo a extraer, y el segundo (opcional), la dirección en la que se extraerá (si no existe, se crea).
>>>exampleZip.extract('spam.txt') 'C:\\spam.txt' >>> exampleZip.extract('spam.txt', 'C:\\some\\new\\folders') 'C:\\some\\new\\folders\\spam.txt' >>> exampleZip.close()
Para crear un nuevo archivo ZIP, se utiliza el método ZipFile(), al iguar que se hacía para leer de su interior:
Para añadir elementos (archivos y directorios) al ZIP, se usará el método write():
>>> import zipfile >>> newZip = zipfile.ZipFile('new.zip', 'w') >>> newZip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED) >>> newZip.close()