Archivos y directorios
Acceso al sistema de archivos local del computador.
Funciones
uint32_t | bfile_dir_work (...) |
bool_t | bfile_dir_set_work (...) |
uint32_t | bfile_dir_home (...) |
uint32_t | bfile_dir_data (...) |
uint32_t | bfile_dir_exec (...) |
bool_t | bfile_dir_create (...) |
Dir* | bfile_dir_open (...) |
void | bfile_dir_close (...) |
bool_t | bfile_dir_get (...) |
bool_t | bfile_dir_delete (...) |
File* | bfile_create (...) |
File* | bfile_open (...) |
void | bfile_close (...) |
bool_t | bfile_lstat (...) |
bool_t | bfile_fstat (...) |
bool_t | bfile_read (...) |
bool_t | bfile_write (...) |
bool_t | bfile_seek (...) |
uint64_t | bfile_pos (...) |
bool_t | bfile_delete (...) |
bool_t | bfile_rename (...) |
1. Sistema de archivos
El sistema de archivos (filesystem) es la estructura jerárquica compuesta por directorios y ficheros que permite organizar los datos persistentes de la computadora (Figura 1). Es algo con lo que los usuarios de ordenadores estamos muy familiarizados, sobre todo tras la irrupción de los sistemas gráficos que introdujeron la analogía de escritorio, carpeta y documento. Comienza en un directorio denominado raíz (/
en Unix ó C:\
en Windows) y, a partir de aquí, cuelgan todos los sub-directorios y ficheros formando un árbol que crece en profundidad. A nivel de programación, el sistema de archivos se gestiona a través de llamadas al sistema que permiten crear directorios, navegar por su contenido, abrir ficheros, eliminarlos, obtener atributos, etc.
- Utiliza bfile_create para crear un nuevo archivo.
- Utiliza bfile_dir_create para crear un directorio.
- Utiliza bfile_dir_open para abrir un directorio con el fin de explorar su contenido.
- Utiliza bfile_dir_get para obtener información sobre una entrada del directorio.
2. Archivos y flujos de datos
Un proceso puede leer o escribir datos en un fichero después de abrir un canal de E/S (Streams) el cual provee un flujo de datos binarios desde o hacia el propio proceso (Figura 2). Existe un puntero que se va desplazando de forma secuencial cada vez que se leen o escriben datos. Inicialmente se encuentra en el byte 0, pero podemos modificarlo para acceder a posiciones aleatorias del archivo sin necesidad de leer el contenido (Figura 3). Esto puede resultar muy útil a la hora de trabajar con ficheros grandes cuyos datos están indexados de alguna manera.
- Utiliza bfile_open para abrir un archivo existente.
- Utiliza bfile_read para leer datos desde un archivo.
- Utiliza bfile_write para escribir datos a un archivo.
- Utiliza bfile_seek para modificar el puntero de archivo.
3. Filename y pathname
Estos dos conceptos son recurrentes y ampliamente utilizados por las funciones del API que manipulan archivos. Cuando navegamos por el contenido de un directorio bfile_dir_get, obtenemos una secuencia de filenames que es el nombre "plano" del elemento (archivo o subdirectorio) sin incluir su ruta dentro del sistema del archivos (sin caracteres '/'
o '\'
). Por otro lado el pathname es una secuencia de uno o varios filenames separados por '/','\'
, que indica el camino a seguir para localizar un determinado elemento. Este camino puede ser absoluto cuando comienza por el directorio raíz (C:\Users\john\docs\images\party.png
) o relativo (docs\images\party.png
) cuando indica la ruta parcial a partir del working directory del proceso.
- Utiliza bfile_dir_work para obtener el directorio de trabajo actual.
- Utiliza bfile_dir_set_work para establecer el directorio de trabajo.
4. Home y AppData
Estos son dos directorios típicos utilizados por las aplicaciones para almacenar los archivos relativos a un determinado usuario. Por un lado, home indica el directorio personal del usuario actualmente registrado en el sistema, típicamente c:\Users\john
(Windows), /home/john
(Linux) ó /Users/john
(macOS). Por otro lado appdata es un directorio reservado para guardar datos temporales o de configuración de las aplicaciones. Localizaciones típicas pueden ser C:\Users\john\AppData\Roaming
(Windows), /home/john/.config
(Linux) ó /User/john/Library
(macOS). Lo habitual será crear una sub-carpeta con el nombre de la aplicación /User/john/Library/TheApp
.
- Utiliza bfile_dir_home para obtener el directorio home del usuario.
- Utiliza bfile_dir_data para obtener el directorio de datos de aplicaciones.
- Utiliza bfile_dir_exec para obtener el directorio del ejecutable.
bfile_dir_work ()
Obtiene el directorio de trabajo actual del proceso (working dir). Es el directorio a partir del cual los pathnames relativos serán interpretados.
uint32_t bfile_dir_work(char_t *pathname, const uint32_t size);
pathname | Búfer donde se escribirá el directorio. |
size | Tamaño en bytes del búfer |
Retorna
El número de bytes escritos en pathname
, incluyendo el carácter nulo '\0'
.
Observaciones
bfile_dir_set_work ()
Cambia el directorio actual de la aplicación (working dir). Los pathname relativos serán interpretados a partir de aquí.
bool_t bfile_dir_set_work(const char_t *pathname, ferror_t *error);
pathname | El nombre del directorio. |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si el directorio de trabajo ha cambiado, FALSE
si ha habido algún error.
Observaciones
bfile_dir_home ()
Obtiene el directorio home
del usuario actual.
uint32_t bfile_dir_home(char_t *pathname, const uint32_t size);
pathname | Búfer donde se escribirá el directorio. |
size | Tamaño en bytes del búfer |
Retorna
El número de bytes escritos en pathname
, incluyendo el carácter nulo '\0'
.
Observaciones
bfile_dir_data ()
Obtiene el directorio AppData donde pueden guardarse datos de configuración de la aplicación.
uint32_t bfile_dir_data(char_t *pathname, const uint32_t size);
pathname | Búfer donde se escribirá el directorio. |
size | Tamaño en bytes del búfer |
Retorna
El número de bytes escritos en pathname
, incluyendo el carácter nulo '\0'
.
Observaciones
bfile_dir_exec ()
Obtiene el pathname absoluto del ejecutable actual.
uint32_t bfile_dir_exec(char_t *pathname, const uint32_t size);
1 2 3 |
char_t path[512]; bfile_dir_exec(path, 512); path = "C:\Program Files\TheApp\theapp.exe" |
pathname | Búfer donde se escribirá el directorio. |
size | Tamaño en bytes del búfer |
Retorna
El número de bytes escritos en pathname
, incluyendo el carácter nulo '\0'
.
bfile_dir_create ()
Crea un nuevo directorio. Fallará si algún directorio intermedio de pathname
no existe.
bool_t bfile_dir_create(const char_t *pathname, ferror_t *error);
pathname | Nombre del directorio a crear, terminado en carácter nulo |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si el directorio ha sido creado, FALSE
si ha habido algún error.
Observaciones
hfile_dir_create crea todos los directorios intermedios de una vez.
bfile_dir_open ()
Abre un directorio para navegar por su contenido. Después hay que utilizar bfile_dir_get para iterar. No se ordenan los filename bajo ningún criterio. Al finalizar, debes llamar a bfile_dir_close.
Dir* bfile_dir_open(const char_t *pathname, ferror_t *error);
pathname | Nombre del directorio, terminado en carácter nulo |
error | Código de error si la función falla. Puede ser |
Retorna
El manejador del directorio o NULL
si se ha producido algún error.
bfile_dir_close ()
Cierra un directorio previamente abierto con bfile_dir_open.
void bfile_dir_close(Dir **dir);
dir | El manejador del directorio. Será puesto a |
bfile_dir_get ()
Obtiene los atributos del archivo actual cuando recorremos un directorio. Previamente hemos de abrir el directorio con bfile_dir_open.
bool_t bfile_dir_get(Dir *dir, char_t *filename, const uint32_t size, file_type_t *type, uint64_t *fsize, Date *updated, ferror_t *error);
dir | Manejador del directorio abierto. |
filename | Aquí se escribirá el nombre del archivo o sub-directorio, terminado en carácter nulo |
size | Tamaño en bytes del búfer |
type | Obtiene el tipo de archivo. Puede ser |
fsize | Obtiene el tamaño del archivo en bytes. Puede ser |
updated | Obtiene la fecha de la última actualización del archivo. Puede ser |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si los atributos del archivo han sido leidos correctamente. Cuando ya no quedan archivos por recorrer, retorna false FALSE
con error=
ekFNOFILES.
Observaciones
Esta función avanzará al siguiente archivo dentro del directorio abierto después de obtener los datos del elemento actual. Si no hay suficiente espacio en name
, retornará FALSE
con error=
ekFBIGNAME y no avanzará al siguiente fichero. Utiliza hfile_dir_loop para navegar por el contenido de un directorio más cómodamente.
bfile_dir_delete ()
Elimina un directorio. Fallará si el directorio no está completamente vacío. Utiliza hfile_dir_destroy para borrar completamente y de forma recursiva un directorio que pueda tener contenido.
bool_t bfile_dir_delete(const char_t *pathname, ferror_t *error);
pathname | Nombre del directorio, terminado en carácter nulo |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si el directorio ha sido eliminado, FALSE
si no.
bfile_create ()
Crea un nuevo archivo. Si previamente ya existía su contenido será borrado. El nuevo archivo será abierto para escritura.
File* bfile_create(const char_t *pathname, ferror_t *error);
pathname | Nombre del archivo incluida su ruta absoluta o relativa. |
error | Código de error si la función falla. Puede ser |
Retorna
El manejador del archivo o NULL
si se ha producido algún error.
bfile_open ()
Abre un archivo existente. No crea el archivo, si no existe la función fallará.
File* bfile_open(const char_t *pathname, const file_mode_t mode, ferror_t *error);
pathname | Nombre del archivo incluida su ruta absoluta o relativa. |
mode | Modo de apertura. |
error | Código de error si la función falla. Puede ser |
Retorna
El manejador del archivo o NULL
si se ha producido algún error.
bfile_close ()
Cierra un archivo previamente abierto con bfile_create o bfile_open.
void bfile_close(File **file);
file | Manejador del archivo. Será puesto a |
bfile_lstat ()
Obtiene los atributos de un archivo a través de su pathname.
bool_t bfile_lstat(const char_t *pathname, file_type_t *type, uint64_t *fsize, Date *updated, ferror_t *error);
pathname | Nombre del archivo incluida su ruta absoluta o relativa. |
type | Obtiene el tipo de archivo. Puede ser |
fsize | Obtiene el tamaño del archivo en bytes. Puede ser |
updated | Obtiene la fecha de la última actualización del archivo. Puede ser |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si ha funcionado correctamente, o FALSE
si no.
bfile_fstat ()
Obtiene los atributos de un archivo a través de su manejador.
bool_t bfile_fstat(File *file, file_type_t *type, uint64_t *fsize, Date *updated, ferror_t *error);
file | Manejador del archivo. |
type | Obtiene el tipo de archivo. Puede ser |
fsize | Obtiene el tamaño del archivo en bytes. Puede ser |
updated | Obtiene la fecha de la última actualización del archivo. Puede ser |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si ha funcionado correctamente, o FALSE
si no.
bfile_read ()
Lee datos desde un archivo abierto.
bool_t bfile_read(File *file, byte_t *data, const uint32_t size, uint32_t *rsize, ferror_t *error);
file | Manejador del archivo. |
data | Búfer donde se escribirán los datos leídos. |
size | El número de bytes máximos a leer. |
rsize | Recibe el número de bytes leídos realmente. Puede ser |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si los datos se han leído correctamente. Si no hay más datos (final del fichero) retorna FALSE
con rsize = 0
y error=
ekFOK.
Observaciones
File stream implementa funciones de alto nivel para lectura/escritura en archivos.
bfile_write ()
Escribe datos en un archivo abierto.
bool_t bfile_write(File *file, const byte_t *data, const uint32_t size, uint32_t *wsize, ferror_t *error);
file | Manejador del archivo. |
data | Búfer que contiene los datos a escribir. |
size | El número de bytes a escribir. |
wsize | Recibe el número de bytes escritos realmente. Puede ser |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si los datos se han escrito, o FALSE
si ha habido algún error.
Observaciones
File stream implementa funciones de alto nivel para lectura/escritura en archivos.
bfile_seek ()
Mueve el puntero de un archivo a una nueva ubicación.
bool_t bfile_seek(File *file, const int64_t offset, const file_seek_t whence, ferror_t *error);
file | Manejador del archivo. |
offset | Número de bytes a desplazar el puntero. Puede ser negativo. |
whence | Posición del puntero a partir de la cual se sumará |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si ha funcionado correctamente, o FALSE
si no.
Observaciones
Retornará FALSE
y error
ekFSEEKNEG si la posición final del puntero es negativa. No es un error establecer un puntero de en una posición más allá del final del archivo. El tamaño del archivo no aumenta hasta que se escriba en él. Una operación de escritura aumenta el tamaño del archivo a la posición del puntero más el tamaño del búfer escrito. Los bytes intermedios quedarían indeterminados.
bfile_pos ()
Retorna la posición actual del puntero de archivo.
uint64_t bfile_pos(const File *file);
file | Manejador del archivo. |
Retorna
Posición a partir de inicio del archivo.
bfile_delete ()
Elimina un fichero del sistema de archivos.
bool_t bfile_delete(const char_t *pathname, ferror_t *error);
pathname | Nombre del archivo incluida su ruta absoluta o relativa. |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si el archivo ha sido eliminado, o FALSE
si ha ocurrido algún error.
bfile_rename ()
Renombra un fichero del sistema de archivos.
bool_t bfile_rename(const char_t *current_pathname, const char_t *new_pathname, ferror_t *error);
current_pathname | Nombre actual del archivo incluida su ruta absoluta o relativa. |
new_pathname | Nuevo nombre del archivo incluida su ruta absoluta o relativa. |
error | Código de error si la función falla. Puede ser |
Retorna
TRUE
si el archivo ha sido renombrado, o FALSE
si ha ocurrido algún error.