Unidad VII
Archivos
7.1 Clases de E/S clase base abstracta
Se quiere la clase base para presentar sólo una interfaz para sus clases derivadas. Esto es, se puede querer que nadie pueda crear un objeto de la clase base y que ésta sirva únicamente para hacer un upcast hacia ella, y poder tener una interfaz. Se consigue haciendo a la clase abstract (abstracta), poniendo como mínimo una función virtual pura. Si alguien intenta hacer un objeto de una clase abstracta, el compilador lo impide. Esta es una utilidad que fuerza a un diseño en concreto.
Cuando se hereda una clase abstracta, hay que implementar todas las funciones virtuales, o la clase que hereda se convierte en una nueva clase abstracta. Crear una función virtual pura permite poner una función miembro en una interfaz sin forzar a proveer un cuerpo con código sin significado para esa función miembro. Al mismo tiempo, una función virtual fuerza a las clases que la hereden a que implemente una definición para ellas.
La clase base abstracta Stream es compatible con bytes de lectura y escritura. Stream tiene compatibilidad asincrónica. Sus implementaciones predeterminadas definen lecturas y escrituras asincrónicas según sus correspondientes métodos asincrónicos, y viceversa.Todas las clases que representan secuencias se derivan de la clase Stream. La clase Stream y sus clases derivadas proporcionan una visión genérica de los orígenes de datos y los repositorios, aislando al programador de los detalles específicos del sistema operativo y sus dispositivos subyacentes.
Las secuencias comprenden estas operaciones fundamentales:
En las secuencias se puede leer: La lectura es la transferencia de datos desde una secuencia a una estructura de datos, como, por ejemplo, una matriz de bytes.
En las secuencias se puede escribir: La escritura consiste en la transferencia de información desde un origen de datos a una secuencia.
Las secuencias pueden admitir operaciones de búsqueda: Las operaciones de búsqueda consisten en la Mconsulta y modificación de la posición actual en una secuencia.
7.2 Realizar entrada y salida de texto
En C un archivo puede ser cualquier cosa, desde un archivo de disco a un terminal o una impresora. Se asocia una secuencia con un archivo específico realizando una operación de apertura, una vez que está abierto, la información puede ser intercambiada entre éste y el programa. El puntero a un archivo es el hilo que unifica el sistema de E/S con buffer. Un puntero a un archivo es un puntero a una información que define varias cosas sobre él, incluyendo el nombre, el estado y la posición actual del archivo. En esencia, el puntero a un archivo identifica un archivo en disco específico y utiliza la secuencia asociada para dirigir el funcionamiento de las funciones de E/S con buffer. Para obtener una variable de tipo puntero a archivo se debe utilizar una sentencia como la siguiente:
FILE *punt;
La función fopen() abre una secuencia para que pueda ser utilizada y le asocia a un archivo. Su prototipo es: FILE *fopen(const char *nombre_archivo, const char *modo); Donde nombre_archivo es un puntero a una cadena de caracteres que representan un nombre válido del archivo y puede incluir una especificación de directorio. La cadena que apunta modo determina cómo se abre el archivo.
Los modos son los siguientes:
r: Abre un archivo de texto para lectura.
w: Crea un archivo de texto par escritura
a: Abre un archivo de texto para añadir
r+: Abre un archivo de texto para lectura/escritura
w+: Crea un archivo de texto para lectura/escritura
a+: Añade o crea un archivo de texto para lectura/escritura
La función fclose() cierra una secuencia que fue abierta mediante una llamada a fopen(). Escribe toda la información que todavía se encuentre en el buffer del disco y realiza un cierre formal del archivo a nivel del sistema operativo. También libera el bloque de control de archivo asociado con la secuencia, dejándolo libre para su reutilización. A veces es necesario cerrar algún archivo para poder abrir otro, debido a la existencia de un límite del sistema operativo en cuanto al número de archivos abiertos.
Su prototipo es:
int fclose(FILE *fp);
La función putc() escribe caracteres en un archivo que haya sido abierto previamente para operaciones de escritura, utilizando la función fopen().
Su prototipo es:
int putc(int car, FILE *pf);
La función getc() escribe caracteres en un archivo que haya sido abierto, en modo lectura, mediante fopen().
Su prototipo es:
int getc(FILE *pf);
La función fputs() escribe la cadena en la secuencia especificada.
Su prototipo es: fputs() escribe la cadena en la secuencia especificada. Su prototipo es: int fputs(const char *cad, FILE *pf);
La función fgets() lee una cadena de la secuencia especificada hasta que se lee un carácter de salto de línea o hasta que se han leído longitud-1 caracteres.
La función rewind() inicia el indicador de posición al principio del archivo indicado por su argumento. Su prototipo es: rewind() inicia el indicador de posición al principio del archivo indicado por su argumento. Su prototipo es:
void rewind(FILE *pf);
Existen otras muchas funciones en la biblioteca estándar de C como pueden ser:
remove(): Borra el archivo especificado.
fflush(): Vacía el contenido de una secuencia de salida.
fread(): Lee tipos de datos que ocupan más de un byte. Permiten la lectura de bloques de cualquier tipo de datos.
fwrite(): Escribe tipos de datos que ocupan más de un byte. Permiten la escritura de bloques de cualquier tipo de datos.
fprintf(): Hace las funciones de printf() sobre un fichero.
fscanf(): Hace las funciones de scanf() sobre un fichero.
feof(): Detecta el final de un fichero.
ferror(): Detecta un error en la lectura/escritura de un fichero.
fclose(): cierra una secuencia que fue abierta mediante una llamada a fopen().
putc(): escribe caracteres en un archivo que haya sido abierto previamente para operaciones de escritura, utilizando la función fopen().
getc(): escribe caracteres en un archivo que haya sido abierto, en modo lectura, mediante fopen(). Su prototipo es:fputs(): escribe la cadena en la secuencia especificada. Su prototipo es: int fputs(const char *cad, FILE *pf);fgets(): lee una cadena de la secuencia especificada hasta que se lee un carácter de salto de línea o hasta que se han leído longitud-1 caracteres. Su prototipo es: fgets() lee una cadena de la secuencia especificada hasta que se lee un carácter de salto de línea o hasta que se han leído longitud-1 caracteres. Su prototipo es:int fgets(char *cad, FILE *pf);
EN C++:Cómo podemos trabajar con un stream simultáneamente en entrada y salida. Para eso usaremos la clase fstream, que al ser derivada de ifstream y ofstream, dispone de todas las funciones necesarias para realizar cualquier operación de entrada o salida.Hay que tener la precaución de usar la opción ios::trunc de modo que el fichero sea creado si no existe previamente.
7.3 Leer y escribir archivos
Leer archivos: Ifstream
Proporciona una interfaz para leer datos de archivos como flujos de entrada. Los objetos de esta clase tratan de mantener internamente un puntero a un objeto filebuf que se pueden obtener llamando a rdbuf miembros.
El archivo que se asocia con la corriente puede ser especificado como un parámetro en el constructor o llamando a los miembros abierta.
Después de todas las operaciones necesarias en un archivo se han realizado, puede ser cerrado (o disociada) llamando a cerrar miembros. Una vez cerrado, el mismo objeto de secuencia de archivo puede ser usado para abrir otro archivo.
El is_open función miembro puede ser usado para determinar si el objeto de secuencia está asociada con un archivo.
Escribir archivos: Ofstream
Proporciona una interfaz para escribir datos en archivos como los flujos de salida. Los objetos de esta clase de mantener internamente un puntero a un objeto filebuf que se pueden obtener llamando a rdbuf miembros.
El archivo que se asocia con la corriente puede ser especificado como un parámetro en el constructor o llamando a los miembros abierta.
Después de todas las operaciones necesarias en un archivo se han realizado, puede ser cerrado (o disociada) llamando a cerrar miembros. Una vez cerrado, el mismo objeto de secuencia de archivo puede ser usado para abrir otro archivo.
El is_open función miembro puede ser usado para determinar si el objeto de secuencia está asociada con un archivo.
7.4 Realizar entrada y salida binaria
Muchos sistemas operativos distinguen entre ficheros de texto y ficheros binarios. Por ejemplo, en MS-DOS, los ficheros de texto sólo permiten almacenar caracteres.En otros sistemas no existe tal distinción, todos los ficheros son binarios. En esencia esto es más correcto, puesto que un fichero de texto es un fichero binario con un rango limitado para los valores que puede almacenar.
En general, usaremos ficheros de texto para almacenar información que pueda o deba ser manipulada con un editor de texto. Un ejemplo es un fichero fuente C++. Los ficheros binarios son más útiles para guardar información cuyos valores no estén limitados. Por ejemplo, para almacenar imágenes, o bases de datos. Un fichero binario permite almacenar estructuras completas, en las que se mezclen datos de cadenas con datos numéricos.
En realidad no hay nada que nos impida almacenar cualquier valor en un fichero de texto, el problema surge cuando se almacena el valor que el sistema operativo usa para marcar el fin de fichero en un archivo de texto. En MS-DOS ese valor es 0x1A. Si abrimos un fichero en modo de texto que contenga un dato con ese valor, no nos será posible leer ningún dato a partir de esa posición. Si lo abrimos en modo binario, ese problema no existirá.
Algunos de los ejemplo anteriores acontoinuación se muestran en binario:
#include
#include
struct tipoRegistro
{
char nombre[32];
int edad;
float altura;
};
int main()
{
tipoRegistro pepe;
tipoRegistro pepe2;
ofstream fsalida("prueba.dat",
ios::out ios::binary);
strcpy(pepe.nombre, "Jose Luis");
pepe.edad = 32;
pepe.altura = 1.78;
fsalida.write(reinterpret_cast(&pepe),
sizeof(tipoRegistro));
fsalida.close();
ifstream fentrada("prueba.dat",
ios::in ios::binary);
fentrada.read(reinterpret_cast(&pepe2),
sizeof(tipoRegistro));
}
Referencias: