Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


5.5.2 Directorios y ficheros en C/C++

§1 Presentación

Las cuestiones relativas al manejo de directorios y ficheros C/C++, están emparentadas con el tratamiento de flujos de E/S, ya que en estos lenguajes, desarrollados originariamente en entornos Unix, el concepto de E/S está íntimamente ligado al concepto genérico de fichero ("File"); cualquier dispositivo externo desde/hacia el que pueda fluir información hacia/desde el programa.

Como muchas otras cuestiones relacionadas con las E/S, la gestión y control de almacenamientos externos (ficheros y directorios de disco) no forman parte de estos lenguajes, sino que se han relegado a una serie de utilidades en la Librería Estándar. Los que hayan utilizado otros lenguajes menos generales, más orientados a las aplicaciones "de gestión", que desde luego suelen hacer uso extensivo de ficheros de disco, sentirán una especial frustración por la escasez, desorganización y falta de uniformidad de las funciones proporcionadas por estas librerías [1]. En consecuencia, las "Suites" de desarrollo. Por ejemplo, C++Builder o Visual C++, suplen esta deficiencia proporcionando cierto número de funciones adicionales que completan las del Estándar, aunque con el grave inconveniente de la falta de portabilidad y de ser soluciones limitadas a plataformas específicas.

La situación es especialmente penosa en las librerías que podríamos denominar de bajo-nivel; heredadas de las funciones tradicionales C. C++ ha venido a aliviar en parte esta situación añadiendo en su Librería un conjunto de clases conocidas con el nombre genérico de iostreams, que se encargan de manejar los flujos de E/S de forma más cómoda para el programador ( 5.3). En este capítulo nos referimos a las primeras; a funciones de la librería C++ heredadas de su antecesor, ya que cualquier el programador C++ las utiliza puntualmente. Además su estudio encierra un gran potencial didáctico.

§2 Sinopsis del manejo de ficheros

En la mayoría de los casos, el manejo de ficheros de disco exige una "apertura" previa del fichero que se desea utilizar (el fichero puede ser creado en el momento de su apertura). En este momento se le asocia un manejador "handle", que puede ser una estructura FILE ( 4.5.5c) o un número (int). A partir de aquí, todas las operaciones sobre el fichero utilizan el handle como identificador. Finalmente, cuando se termina su utilización, el fichero es "cerrado".  Excepcionalmente algunas funciones que solo aportan información sobre ficheros determinados por un path-name, no se requiere la "apertura" previa ni la existencia de un "handle".

La apertura de ficheros puede efectuarse de varias formas; cada una de estas "formas" establece ciertas condiciones sobre el fichero y el modo en que podrá ser utilizado a partir de ese momento. Por ejemplo: puede establecerse que el fichero solo será utilizado para lectura, o que se creará nuevo si no existe otro de igual nombre; o que si existe otro de igual nombre, será borrado y sustituido por otro vacío; que las operaciones de L/E serán binarias o de texto ( 5.3), Etc.

La tabla adjunta muestra las formas de apertura establecidas por la función fopen de la librería clásica (consulte en el manual de su compilador los detalles de esta y las demás funciones).

Modo Descripción
"w" Crear para escritura. Si el fichero existe con anterioridad será sobreescrito. El modo (binario o texto) depende de la variable globlal _fmode.
"w+" Crear para lectura/escritura. Si el fichero existe con anterioridad será sobreescrito. Idem. Idem. respecto al modo.
"wb" Crear para escritura en modo binario. Si el fichero existe con anterioridad será sobreescrito.
"w+b" Crear para lectura/escritura en modo binario. Si el fichero existe con anterioridad será sobreescrito.
"a" Abrir en modo escritura para añadir al final. Si el fichero no existe es creado. Idénticas consideraciones sobre el modo (binario/texto) que en el primer caso (depende de _fmode).
"ab" Abrir en modo escritura binaria para añadir al final. Si el fichero no existe, es creado.
"r" Abrir para lectura. Si el fichero no existe se produce un error. El modo binario/texto depende de _fmode como en el primer caso.
"r+" Abrir un fichero existente para lectura y escritura. Si el fichero no existe se produce un error. Idem. Idem. respecto al modo.
"rb" Abrir para lectura en modo binario. Si el fichero no existe se produce un error.
"r+b" Abrir un fichero existente para lectura y escritura en modo binario. Si el fichero no existe se produce un error.


Nota
: las operaciones en modo texto suponen ciertas conversiones de los caracteres leídos/escritos con los realmente recibidos o grabados en el disco (de forma que no se lee exactamente lo que existe en el disco y a la inversa). Los detalles dependen de la implementación, pero se resumen en que durante los procesos de lectura, los pares CR-LF son transformados en un solo carácter LF. Por contra, en las operaciones de salida los caracteres LF son escritos como combinaciones CR-LF. Además de esto, en las operaciones de lectura el carácter 26 decimal SUB (CTRL+Z) es interpretado como fin de fichero (EOF = End Of File), y las rutinas de escritura en modo texto insertan este carácter al final.


Las operaciones de lectura/escritura a ficheros de disco exigen incluir en el fuente las cabeceras <stdio.h> o <cstdio> (esta última es la versión moderna de la primera), e implican ciertos parámetros mantenidos automáticamente por el Sistema.  Los más significativos para el programador son:

  • File-pointer (abreviadamente fp). Un puntero que señala el punto a partir del que se efectuará la próxima operación de L/E. Estas operaciones suponen la lectura o escritura de un número determinado de caracteres a partir de la posición inicial del file-pointer.  Dependiendo de la "forma" en que sea abierto un fichero, el fp puede ser situado automáticamente en la posición 0 (comienzo) o al final. Las operaciones de L/E mueven automáticamente el fp hacia adelante en función del número de caracteres leídos/escritos, de forma que las sucesivas operaciones se efectúan siempre en posiciones a partir de la última. Cuando el fp alcanza el final del fichero (EOF) en operaciones de lectura, se alcanza un estado especial que puede ser interrogado por el programa (ver función feof ).  También existen funciones que permiten situar el fp en un punto arbitrario del fichero para que las futuras operaciones se realicen a partir de dicha posición (fseek , fsetpos ).

  • Marca de error:  Una señal de estado que indica si la última operación ha concluido satisfactoriamente o se ha producido un error.

  • Marca de fin de fichero EOF ("End of File"). Indica si la operación ha alcanzado o no el fin de fichero.

  • Marca de inicio de fichero BOF ("Begin of File"). Señala si se ha alcanzado el principio del fichero.

Los detalles de su comportamiento dependen de la plataforma, pero son importantes de conocer. Por ejemplo, si la marca de fin de fichero está activada, no pueden efectuarse ciertas operaciones en el disco hasta que sea quitada mediante una operación de reposicionado del fp.

§3 Resumen de funciones

Con objeto de proporcionar una visión general de las posibilidades al respecto, se incluye una tabla-resumen (no exhaustiva) con las principales funciones C/C++ para gestión de ficheros y directorios ofrecidas por el compilador Borland C++ (que coincide substancialmente con el "Visual" de MS).

Nota: algunas de las funciones expuestas no se refieren exclusivamente a operaciones con ficheros de disco. En realidad se refieren a flujos ("Streams") de E/S con dispositivos genéricos. Sin embargo, aquí las presentamos bajo la perspectiva de su utilización con L/E a ficheros de disco.


La tabla, incluye el nombre de la función; una breve descripción de su funcionalidad; una indicación del tipo de "Handle" utilizado para su manejo, y datos sobre su portabilidad.

  • Handle HF indica que el handle utilizado o devuelto por la función es una estructura FILE ( 4.5.5c) [3]; I señala que es un número entero (int) [4]. Finalmente, la ausencia de tipo indica que es una función para manejo de directorios o que la función no se refiere al fichero mediante su manejador, sino mediante su identificador completo ("Path-name").

  • Descripción: la tabla no pretende ser un sustituto del manual del compilador. Solo una breve reseña que ayude a identificar rápidamente que función puede servir a nuestros propósitos. Junto a algunas entradas se han incluido referencias a otras funciones relacionadas. Las referencias a "discos". Por ejemplo: número de disco actual, se refieren al volumen lógico. Aunque también pueden ser otros dispositivos ("Current drive").

  • Compatibilidad: indica si la función comentada puede ser utilizada en UNIX; Windows32; ANSI C y ANSI C++.

§3.1 Tabla-resumen
Nombre Descripción H. UNIX W32 C C++
access Determina la existencia del fichero y el tipo de acción posible sobre él (lectura, escritura, ejecución) (filelength , stat ) - X X - -
chdir Cambiar el directorio actual (getcurdir , getcwd , getdisk , mkdir , rmdir - X X - -
chmod Cambiar el tipo de acceso permitido a un fichero (Lectura, Escritura o L/E). Ver _rtl_chmod - X X - -
chsize Cambiar (aumentar o disminuir) el tamaño de un fichero I - X - -
closedir Cerrar un directorio-stream (opendir readddir , rewinddir ) - X X - -
_creat Crear un fichero nuevo definido por su path-name (umask ) I X X - -
creattemp Crear un fichero de nombre único en un directorio (útil para ficheros temporales) I - X - -
dup Crar un nuevo handle a partir de otro existente. El nuevo tiene en común con el antiguo: fichero asociado; fp, y modo de acceso. I X X - -
dup2 Similar al anterior I X X - -
eof Determinar si el handle ha alcanzado el final de ficheo ("End Of File") I - X - -
fclose Cerrar un fichero F X X X X
_fdopen Permite crear un nuevo flujo (definido por un handle F) y asociarlo con un handle I obtenido con _creat , dup , dup2 o open F/I X X - -
feof Detectar si se ha alcanzado el final de fichero después de una operación de lectura F X X X X
ferror Detectar si se ha producido error después de una operación de L/E en el fichero (perror ) F X X X X
fflush Forzar el vaciado del buffer de salida ( 5.3.4), y consiguiente escritura de datos al disco (setbuf , setvbuf ). F X X X X
fgetc Leer el próximo carácter del fichero F X X X X
fgetpos Obtener la posición actual del fp de un fichero (es complementaria de fsetpos ) F - X X X
fgets Leer un número de caracteres de un fichero F X X X X
findclose Cierra cualquier handle y libera la memoria dinámica asociada con invocaciones previas a findfirst y findnext - - X - -
findfirst Comienza la búsqueda de ficheros definidos por atributos o comodines en un directorio de disco (searchenv , searchpath , searchstr ) - - X - -
findnext Continúa la búsqueda iniciada con findfirst - - X - -
filength Obtener el tamaño en bytes de un fichero (stat ) I - X - -
_fileno Obtener el número de manejador asociado a un handle tipo FILE. F/I X X - -
fnmerge Construir un path-name a partir de sus componentes (fullpath makepath , splitpath , fullpath ) - - X - -
fnsplit Desmembrar un path-name en sus componentes (fnmerge , fullpath ) - - X - -
fopen Abrir un fichero en diversos modos (lectura, escritura, crearlo si no existe, etc). open , freopen F X X X X
fprintf Componer y formatear una una cadena de caracteres y escribir el resultado en un fichero F X X X X
fputc Escribir un carácter en un fichero (similar a putc ) F X X - -
fputs Escribir una matriz C ( 3.2.3f) en un fichero F X X X X
fread Leer n items de tamaño t bytes de un fichero almacenándolos en un buffer (ver fwrite ). F X X X X
freopen Asociar un nuevo fichero a un manejador (handle) previamente asociado a otro fichero abierto. open , fopen F X X X X
fscanf Leer una serie de campos de un fichero formateando los datos recibidos F X X X X
fseek Esta blecer una nueva posición para el fp de un fichero abierto (similar a rewind ; lseek ) F X X X X
fsetpos Establecer el fp asociado a un fichero a una posición obtenida previamente con fgetpos   F - X X X
fstat Fijar datos (tamaño, último acceso, etc) relativos a un fichero o directorio. Inversa a stat I X X - -
ftell Obtener la posición actual (bytes desde el origen) del fp de un fichero (fseek , tell , lseek ) F X X X X
fullpath Convertir un path-name relativo en absoluto (fnsplit , makepath , splitpath ) - - X - -
fwrite Escribir n items de tamaño t bytes de un buffer en un fichero (complementaria de fread ) F X X X X
getc Lee el próximo carácter del fichero (similar a fgetc ) F X X X X
getcurdir Obtener el nombre del directorio activo en un volumen lógico determinado (getdisk , getdrive , setdisk ) - - X - -
getcwd Obtener el nombre del directorio activo actual incluyendo nombre del disco (getdisk , getdrive , setdisk ) - - X - -
getcdwd Similar al anterior - - X - -
getdisk Obtener el número del disco actual (getcurdir , getdrive , setdisk ) - - X - -
_getdrive Obtener el número del disco actual (getcurdir , getcwd ) - ? X ? ?
getftime Obtener los datos de fecha y hora de un fichero (complementaria de setftime ) I - X - -
lock Bloquear un fichero.  Junto con unlock es una interfaz con el sistema de bloqueo del SO I - X - -
locking Bloquear y desbloquear una porción de un fichero I - X - -
lseek Mueve el fp de un fichero a una nueva posición (tell , fseek , ftell ) I X X - -
_makepath Construir un path-name a partir de sus componentes (fnmerge splitpath ) - - X - -
mkdir Crear un directorio (rmdir ) - X X - -
_mktemp Crea un nombre de fichero único a partir de una plantilla de la forma "ABC..Exx.xxx rellenando los seis últimos caracteres (tmpfile tempnam ) - X X - -
open Abrir un fichero en diversos modos. fopen ; freopen , umask I X X - -
opendir                            (closedir , readddir , rewinddir ) - X X - -
perror Escribir en el buffer estándar de salida.          
_pipe Establece un fichero en memoria que puede servir para compartir datos entre procesos I - X - -
_popen Crea un "pipe" con el procesador de comandos   - X - -
putc Escribe un carácter en un fichero F X X X X
read Leer n bytes de un fichero y almacenarlos en un buffer. I X X - -
readdir                           (closedir , opendir rewinddir ) - X X - -
remove Borrar un fichero definido por su path-name (es una macro que invoca a _unlink ) - X X X X
rename Permite renombrar un fichero dentro de un directorio y/o moverlo de directorio - - X X X
rewind Posicionar el fp al principio del fichero. Similar a fseek ,aunque con diferencias de matiz F X X X X
rewinddir                (closedir , opendir readddir ) - X X - -
rmdir Borrar un directorio (mkdir ) - X X - -
_rmtmp Borrar los ficheros temporales previamente creados con tmpfile (mktemp ) - - X - -
_rtl_chmod Obtener/cambiar los atributos del fichero (similar aunque más amplio que chmod ) - X X X -
_rtl_close Cerrar un fichero previamente abierto con _rtl_creat I X X X -
_rtl_creat Crear un fichero y abrirlo para L/E binario (pueden ser ficheros ocultos o de Sistema) I X X X -
_rtl_open Abrir un fichero para L, E o L/E binario I - X - -
_rtl_read Leer n bytes de un fichero I X X X -
_rtl_write Escribir n bytes en un fichero I X X X -
_searchenv Busca un fichero en un path de entorno; PATH, LIB, INCLUDE, etc. (findfirst , searchpath , searchstr ) - - X - -
searchpath Buscar un fichero determinado en las direcciones señaladas por la variable de entorno del Sistema: PATH=... (searchenv , findfirst , searchstr ) - - X - -
_searchstr Buscar un fichero en una lista de directorios (searchenv , searchpath , findfirst ) - - X - -
setbuf Utilizar un buffer específico para las operaciones de E/S de un flujo en lugar del establecido por el Sistema. Los caracteres almacenados en el buffer permanecen en él hasta que es vaciado por alguna causa (fflush ) F X X X X
setdisk Establecer el número del disco actual (getdisk , getcurdir , getcwd ) - - X - -
setftime Establecer los datos de fecha y hora de un fichero (complementaria de getftime ; _utime ) I - X - -
setmode Fijar el modo de L/E (binario/texto) de un fichero abierto previamente en otro modo I - X - -
setvbuf Utilizar un buffer específico en lugar del proporcionado por el Sistema para operaciones de E/S asociadas a un fichero. Permite establecer la forma en que se manejará el buffer. F X X X X
_seplitpath Desmembrar un path-name en sus componente (makepath ) - - X - -
stat Obtener información (tamaño, último acceso, etc) relativa a un fichero o directorio. Inversa a fstat (filelength , access ) - X X - -
system Invocar el intérprete de comandos del SO para ejecutar un comando   X X - -
tell Obtener la posición actual (bytes desde el inicio) del fp de un fichero (lseek , ftell ) I X X - -
_tempnam Obtener un nombre de fichero no utilizado en un directorio. Es posible especificar los 5 primeros caracteres de este nombre; el resto son proporcionados aleatoriamente por el Sistema (tmpfile ). - X X - -
tmpfile Crea un fichero temporal de nombre aleatorio y lo abre para lectura-escritura binaria. El fichero es destruido automáticamente al cerrarlo o al terminar el programa (rmtmp , tempnam , mktemp ) F X X X X
umask Establecer los parámetros de L/E utilizados por las funciones open y _creat - - X - -
_unlink Borrar un fichero definido por su path-name (ver remove ) - X X - -
unlock Desbloquear un fichero previamente bloqueado con lock . I - X - -
_utime Permite establecer la fecha/hora de modificación de un fichero a un valor determinado (setftime ) - X X - -

  Inicio.


[1]  Esta percepción es especialmente intensa si se ha tenido ocasión de utilizar alguna de las riquísimas colecciones de utilidades proporcionadas por algunos compiladores de aplicaciones de bases de datos. Personalmente el uso de las utilidades de ficheros y disco de la Librería Estándar me ha producido la sensación de utilizar un palo y una piedra para reparar un automóvil.

[3] Cualquiera de las funciones que utilizan una estructura FILE como manejador pueden ser también utilizadas con los "ficheros" estándar de E/S, que tienen la propiedad de ser abiertos automáticamente por el programa ( 5.3). Por ejemplo:

fputs("Hello world\n", stdout);

[4] Existe una utilidad (_fileno) que permite calcular el número I correspondiente a un handle F