Micropython: Aprendiendo a utilizar el sistema de archivos. Parte 1

Micropython es mucho mas que un simple intérprete e incluye funciones que son propias de sistemas operativos, como un sistema de archivos para guardar nuestros programas y librerías, así como para almacenar información. En este artículo veremos como funciona ese sistema de archivos y como podemos emplearlo para guardar información.

Sistema de archivos de Micropython

Un sistema de archivos no es otra cosa que un mecanismo que nos permite guardar información en un medio de almacenamiento que puede ser no volátil como la memoria Flash o una tarjeta SD o volátil, como la memoria RAM. Generalmente permite construir una estructura jerárquica, como las carpetas y sub-carpetas a las que estamos acostumbrados en Windows o Linux en las que se almacenan las unidades de información denominadas archivos. También nos provee de instrucciones o comandos para borrar, renombrar o mover los archivos entre carpetas y para leer su contenido y eventualmente modificarlo.

Para mantener organizado un sistema de archivos, el micro debe mantener estructuras de datos que indiquen donde están ubicados los archivos, que espacio está ocupado y cual queda libre, etc. Esto puede implementarse de distintas maneras, por lo que tenemos distintos tipos de sistemas de archivos, como FAT o NTFS en Windows, EXT en Linux o LittleFS, un sistema de archivos robusto diseñado especialmente para microcontroladores o sistemas embebidos.

En el caso de Micropython, el tipo de sistema de archivos puede cambiar según el port, según la versión que utilicemos para un micro o placa en particular. Por ejemplo se utiliza LittleFS en ESP32, ESP8266 y Raspberry Pi Pico pero FAT en STM32.

Afortunadamente la mayoría de las veces no debemos preocuparnos de la organización interna del sistema de archivos y podemos aprovechar sus funciones de manera transparente en cualquier placa.

Funciones generales

Vamos a probar ahora algunas funciones generales para administrar el sistema de archivos. Para ello usaremos el intérprete interactivo o REPL al que podemos acceder desde la consola de Thonny, Mu y la mayoría de IDEs. En este caso usaré Thonny y una placa ESP32 con Micropython 1.16 recién instalado al que además le grabé el programa main.py

Para acceder a las funciones del sistema de archivos debemos importar antes el modulo os, así que primero escribimos:

A continuación podemos probar distintas funciones. Por ejemplo, para listar el contenido del sistema de archivos usamos listdir ():

Que nos muestra los dos archivos boot.py y main.py

También podemos crear un directorio usando mkdir(“nombre”) y entrar al mismo con chdir(“nombre”). En el siguiente ejemplo se crea el directorio “Lib”, entramos a él y al listar los archivos vemos que está vacío.

Para salir de este directorio y volver a la raíz del sistema de archivos volvemos a usar chdir. Si queremos borrar un directorio debemos usar rmdir (“Nombre”) siempre que el directorio este vacío:


Si queremos saber en que directorio estamos podemos usar getcwd():

También podemos renombrar un directorio después de crearlo con rename(“Nombre_viejo”, “Nombre_nuevo”), como en el siguiente ejemplo en que se crea un directorio llamado “Img” y luego se lo cambia a “GIF”:

Todas estas funciones también pueden ser usadas dentro de un programa, además de ser invocadas en la consola como en estos ejemplos.

Resumen

listdir – Lista el contenido del sistema de archivos

mkdir – Crea un directorio

chdir – Cambia a un directorio

rmdir – Borra un directorio

getcwd – Indica el directorio actual

rename – Renombra un directorio o archivo

Creando y leyendo archivos

Llegamos ahora a la parte mas interesante, que es grabar y leer algún tipo de información dentro de archivos. Esto puede ser útil para guardar datos de configuración, ajustes o, como veremos en otro ejemplo, construir un data logger que almacene información proveniente de sensores para ser luego descargada y analizada.

Escribiendo en un archivo

Empecemos creando un archivo y guardando datos en él. Para crearlo usamos la instrucción open indicando que queremos escribir datos. Como es la primera vez que lo hacemos y el archivo no existe, éste se creará. La sintaxis a utilizar es:

objeto_archivo  = open("nombre", "modo") 

Donde objeto_archivo es un objeto que contiene métodos y atributos para realizar distintas operaciones sobre el archivo, nombre es el nombre que tendrá el archivo y modo indica la forma en que abrimos el archivo y define qué operaciones se pueden realizar sobre él:

En este caso creamos el archivo con el nombre archivo.dat en modo escritura, por eso usamos la w.

Por ahora archivo.dat está vacío, si queremos escribir información en él debemos hacerlo con el método write:

Como se puede ver, este método devuelve la cantidad de bytes que se almacenaron cada vez que se lo utilizó.

Cuando terminamos de guardar datos en el archivo debemos cerrarlo. Esto nos asegura que toda la información quede correctamente grabada. Para ello empleamos el método close:

Atención

Siempre se deben cerrar los archivos con close para evitar pérdida de información

Para ver el contenido del archivo podemos abrirlo con Thonny:

Leyendo un archivo

También podemos leer el contenido del archivo con el método read, si primero lo abrimos con open:

En este caso como no especificamos el modo en open, Micropython asume que es modo lectura. También podemos explicitarlo usando el modo r (read):

Ahora bien, cuando escribimos en el archivo, enviamos tres datos, “Uno”, “Dos” y “Tres” pero al leer, leemos el archivo completo, obteniendo todos los textos unidos. Si queremos separar cada uno de los textos como datos individuales, deberemos terminarlos con el carácter de retorno de carro “\n”, que sirve como un separador:

Y al leer el archivo, en vez de utilizar el método read(), debemos emplear readline(), que lee una línea, es decir todo el texto hasta el caracter “\n”:

Como se puede ver en el ejemplo anterior, debemos leer varias veces el archivo para ir sacando los datos de a uno. Si seguimos leyendo cuando ya no hay datos, Micropython nos devuelve un caracter vacío ”.

Resumen

open – Abre un archivo para leer (r) o escribir (w)

write – Escribe un texto en el archivo

read – Lee el archivo completo

readline – Lee una línea del archivo

El método read nos permite especificar la cantidad de caracteres a leer. Por ejemplo, si no usamos el retorno de línea como separador y guardamos datos con una longitud fija, tales como números que tienen siempre tres caracteres (como “001”, “054” o “999”) podemos ir leyendo el archivo de tres en tres caracteres. Veamos como funciona:

Ejemplo: Data Logger

Vamos a aplicar lo aprendido hasta ahora a un data logger rudimentario. Un data logger es un instrumento registrador que realiza mediciones a través de distintos sensores y los almacena en memoria junto a la fecha y hora, para poder tener una referencia temporal cuando se analicen los datos.

Como primer paso vamos a guardar sólo fecha y hora, luego lo complementaremos con información de algún sensor.

Veamos el siguiente código:

import time

while (True):

    #Obtener fecha y hora
    fecha_hora = (time.localtime())
    
    #Separar campos
    dia=fecha_hora [2]
    mes=fecha_hora[1]
    hora = fecha_hora [3]
    min = fecha_hora [4]
    seg = fecha_hora [5]
    
    #Dar formato de dos digitos
    info_tiempo = "{:02}".format (dia)+"{:02}".format(mes)+"{:02}".format(hora) + "{:02}".format(min) + "{:02}".format(seg)
    print (info_tiempo)
    
    #Grabar en archivo
    file=open ("datos.dat","w")
    file.write (info_tiempo + "\n")
    file.close ()

    time.sleep (2)

Analicemos su funcionamiento:

En la línea 6 se obtiene la información de fecha y hora a partir del reloj interno. Recuerden como vimos en un artículo anterior que este reloj no es preciso y no reemplaza a un reloj de tiempo real. También que Thonny lo actualiza cada vez que descargamos un programa. Si no usan Thony deberán cargar los valores correctos de fecha y hora a mano con la instrucción localtime()

Desde la línea 9 a la 13 se toman los valores de interés de la tupla devuelta por localtime() a distintas variables.

En la línea 16 se construye una cadena de texto con los valores de día, mes, hora, minutos y segundos, todos con dos decimales para tener una longitud constante.

En las líneas 20, 21 y 22 se abre el archivo para escritura, se escribe la cadena de texto mas el símbolo retorno de carro como separador y se cierra el archivo.

Finalmente en la línea 24 se hace una demora de dos segundos antes de grabar un nuevo valor.

Añadiendo datos

Pero este código tiene un problema: si abren el archivo “datos.dat” en Thonny, verán que en vez de contener varios datos separados por dos segundos, contiene sólo la cadena de texto correspondiente al último valor. Eso es porque cada vez que abrimos el archivo en el modo w borramos el contenido anterior del archivo. Para corregirlo, cambiaremos el modo a “append” (agregar):

import time

while (True):

    #Obtener fecha y hora
    fecha_hora = (time.localtime())
    
    #Separar campos
    dia=fecha_hora [2]
    mes=fecha_hora[1]
    hora = fecha_hora [3]
    min = fecha_hora [4]
    seg = fecha_hora [5]
    
    #Dar formato de dos digitos
    info_tiempo = "{:02}".format (dia)+"{:02}".format(mes)+"{:02}".format(hora) + "{:02}".format(min) + "{:02}".format(seg)
    print (info_tiempo)
    
    #Grabar en archivo
    file=open ("datos.dat","a")
    file.write (info_tiempo + "\n")
    file.close ()

    time.sleep (2)

La instrucción de la línea 20 abre el archivo para agregar datos al final, sin borrar el contenido anterior. Si el archivo no existe, lo crea y agrega los datos.

Ahora si, después de un tiempo tenemos en el archivo varias lecturas:

Conclusión

Hicimos una introducción al sistema de archivos de Micropython y vimos las funciones y métodos disponibles para manejar directorios y archivos. También vimos como grabar información en un archivo y como leerla.

En todos los casos trabajamos con cadenas de texto, sin embargo los archivos se pueden utilizar también con datos binarios, para lo cual se emplean algunos métodos adicionales. Ese tema será el contenido del próximo artículo de esta serie.

Navegación de la serieMicropython: Aprendiendo a utilizar el sistema de archivos. Parte 2 >>

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Habilitar notificaciones OK No, gracias