Existen muchas utilerías que permiten manipular directorios y archivos. Los comandos cd
, ls
, rm
, cp
, mkdir
, etc. son ejemplos que han sido revisados ya en el sistema operativo.
Se revisará en este capítulo como hacer las mismas tareas dentro de un programa en C.
Para realizarlo se requiere llamar las funciones apropiadas para recorrer la jerarquía de directorios o preguntar sobre los contenidos de los directorios.
path
.
path
es un apuntador a una cadena donde la trayectoria será regresada. La función devuelve un apuntador a la cadena o NULL si un error ocurre.
Se tiene a continuación la emulación del comando cd
de Unix con C:
#include <stdio.h> #include <unistd.h> #define TAM 80 main(int argc, char **argv) { char cadena[TAM]; if (argc < 2) { printf("Uso: %s <directorio> \n",argv[0]); exit(1); } if (chdir(argv[1]) != 0) { printf("Error en %s.\n",argv[0]); exit(1); } getcwd(cadena,TAM); printf("El directorio actual es %s\n",cadena); }
Dos funciones útiles (en plataformas BSD y aplicaciones no multi-thread) están disponibles:
int scandir(const char *dir, struct dirent **listanomb,
int (*select)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **)
Esta función rastrea el directorio dir
, llamando select()
en cada entrada de directorio. Las entradas para las que select()
devuelve un valor distinto de cero se almacenan en cadenas que se asignan de la memoria con malloc()
, ordenadas usando qsort()
con la función de comparación compar()
, y puestas en la matriz listanomb
. Si select
es NULL, se seleccionan todas las entradas.
int alphasort(const struct dirent **a, const struct dirent **b);
Puede ser usada como función de comparación para que la función scandir()
ponga las entradas de directorio en orden alfabético.
A continuación se tiene una versión simple del comando de UNIX ls
#include <dirent.h> #include <unistd.h> #include <sys/param.h> #include <stdio.h> #define FALSO 0 #define VERDADERO !FALSO extern int alphasort(); char trayectoria[MAXPATHLEN]; main() { int contar,i; struct dirent **archivos; int selecc_arch(); if ( getwd(trayectoria) == NULL ) { printf("Error obteniendo la trayectoria actual\n"); exit(0); } printf("Directorio de trabajo actual: %s\n",trayectoria); contar = scandir(trayectoria, &archivos, selecc_arch, alphasort); /* Si no se encontraron archivos */ if (contar <= 0) { printf("No hay archivos en este direntorio\n"); exit(0); } printf("Hay %d archivos.\n",contar); for (i=0; i<contar; ++i) printf("%s ",archivos[i]->d_name); printf("\n"); /* flush buffer */ } int selecc_arch(struct dirent *entry) { if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) return (FALSO); else return (VERDADERO); }
scandir
regresa los pseudodirectorios (.
), (..
)
y también todos los archivos. En este ejemplo se filtran los
pseudodirectorios para que no se muestren haciendo que la función
regrese FALSO
.
Los prototipos de las funciones scandir
y alphasort
tienen definiciones en la cabecera dirent.h
MAXPATHLEN
esta definida en sys/param.h
y la función getwd()
en unistd.h
.
Se puede ir más lejos que lo anterior y buscar por archivos particulares.
Reescribiendo la función selecc_arch
para que sólo muestre los archivos con los sufijos .c
, .h
y .o
.
int selecc_arch(struct dirent *entry) { char *ptr; if ((strcmp(entry->d_name, ".")== 0) || (strcmp(entry->d_name, "..") == 0)) return (FALSO); /* Revisar las extensiones de los archivos */ ptr = rindex(entry->d_name, '.'); /* Probar que tenga un punto */ if ( (ptr != NULL ) && ( (strcmp(ptr, ".c") == 0) || (strcmp(ptr, ".h") == 0) || (strcmp(ptr, ".o") == 0) ) ) return (VERDADERO); else return(FALSO); }
La función rindex()
es una función para manejo de cadenas que regresa un apuntador a la última ocurrencia del caracter c
en la cadena s
, o un apuntador NULL si c
no ocurre en la cadena. (index()
es una función similar pero asigna un apuntador a la primera ocurrencia.)
Existen varias llamadas al sistema que pueden ser aplicadas directamente a los archivos guardados en un directorio.
La función int access(const char *trayectoria, int modo);
-- determina los permisos de usuario para un fichero, de acuero con modo
, que esta definido en #include <unistd.h>
, los cuales pueden ser:
La función access()
regresa: 0 si ha habido éxito, o -1 en caso de falla y a errno
se le asigna un valor adecuado. Ver las páginas del man
para ver la lista de errores.
Algunas llamadas al sistema (y algunas funciones de biblioteca) dan un valor al entero errno
para indicar que ha habido un error. Esta es una variable especial del sistema.
Para usar errno
en un programa de C, debe ser declarado de la siguiente forma:
extern int errno;
Esta puede ser manualmente puesto dentro de un programa en C, de otra forma simplemente retiene el último valor.
La función int chmod(const char *trayectoria, mode_t modo);
cambia el modo del archivo dado mediante trayectoria
para un modo dado.
chmod()
devuelve 0 en caso de éxito y -1 en caso de error además se asigna a la variable errno
un valor adecuado (revisar las páginas de man
para ver los tipos de errores)
Se tienen dos funciones útiles para conocer el estado actual de un archivo.
Por ejemplo se puede sabe que tan grande es un archivo (st_size), cuando fue
creado (st_ctime), etc (ver la definición de la estructura abajo). Las dos funciones tienen sus prototipos en
<sys/stat.h>
nomb_arch
. No se
requieren permisos de lectura, escritura o ejecución, pero todos los
directorios listados en nomb_arch
deberán estar disponibles.
desarch
(tal y como lo devuelve open()
) es examinado en lugar de
nomb_arch
.
Las funciones stat()
y fstat()
regresan 0 en caso éxito, -1 si
hubo error y errno
es actualizado apropiadamente.
buf
es un apuntador a la estructura stat
en la cual la
información es colocada. La estructura stat
esta definida en
include <sys/stat.h>
, como sigue:
struct stat { dev_t st_dev; /* dispositivo */ ino_t st_ino; /* inodo */ mode_t st_mode; /* proteccion */ nlink_t st_nlink; /* numero de enlaces fisicos */ uid_t st_uid; /* ID del usuario propietario */ gid_t st_gid; /* ID del grupo propietario */ dev_t st_rdev; /* tipo dispositivo (si es dispositivo inodo) */ off_t st_size; /* tamaño total, en bytes */ unsigned long st_blksize; /* tamaño de bloque para el sistema de ficheros de E/S */ unsigned long st_blocks; /* numero de bloques asignados */ time_t st_atime; /* hora ultimo acceso */ time_t st_mtime; /* hora ultima modificacion */ time_t st_ctime; /* hora ultimo cambio */ };
Se muestra un ejemplo que hace uso de la función stat
:
#include <stdio.h> #include <sys/stat.h> /* Para la estructura stat */ #include <unistd.h> main(int argc, char **argv) { struct stat buf; printf("%s\n",argv[0]); if ( stat(argv[0], &buf) == -1 ) { perror(argv[0]); exit(-1); } else { printf("Tamaño del archivo %s %d bytes.\n",argv[0],buf.st_size); } }
Existen algunas funciones para borrar y renombrar archivos. Quizás la forma
más común es usando las funciones de stdio.h
:
int remove(const char *pathname); int rename(const char *viejo, const char *nuevo);
Dos llamadas al sistema (definidas en unistd.h
) las cuales son
actualmente usadas por las funciones remove()
y rename()
también existen, pero son probablemente más díficiles de recordar, al
menos que se este suficientemente familiarizado con UNIX.
errno
para indicarlo.
Las funciones stat()
y fstat()
regresan 0 en caso éxito, -1 si
hubo error y pone la variable errno
con algún valor indicando el
tipo de error.
Los programas con frecuencia necesitan crear archivos sólo durante la vida de un programa. Existen dos funciones convenientes (además de algunas variantes) para la realización de la tarea mencionada. El manejo (borrado de archivos, etc.) es tomado con cuidado por el sistema operativo.
La función FILE *tmpfile (void);
crea un archivo temporal (en modo de
lectura/escritura binaria) y abre el correspondiente flujo. El archivo se
borrará automáticamente cuando el programa termine.
La función char *tmpnam(char *s);
crea un nombre único para un
archivo temporal usando el prefijo de trayectora P_tmpdir
definido en
<stdio.h>
.
ls -l
de UNIX
que muestre todos los archivos del directorio actual, sus permisos, tamaño,
etc.
grep
de UNIX.
more
de UNIX).