Archivos de texto y archivo binario

Archivo de Texto
Archivo que utiliza solamente caracteres del estándar ASCII y, por lo tanto, que puede ser enviado por correo electrónico sin ningún tipo de modificación.La apertura y lectura de archivos para acceso de lectura es una parte importante de la funcionalidad de entrada y salida (E/S), incluso si no necesita escribir en el archivo en cuestión. En este ejemplo se abre un archivo para lectura. Esto es útil para leer archivos de texto pero no funciona para archivos binarios. En este ejemplo se utiliza uno de los diversos métodos disponibles para abrir el archivo.

Aunque existen muchas estructuras de datos para almacenar información recuperada del archivo, ArrayList es la más fácil de utilizar. Para abrir y leer del archivo se utilizan objetos del espacio de nombres System.IO, en concreto la clase System.IO.StreamReader.

NOTA: para este ejemplo necesitará un archivo de texto (.txt) del que leer.

Para intentar cargar y leer un archivo de texto desde Visual C++ .NET, siga estos pasos:
1. Abra Visual Studio .NET. Cree una nueva aplicación de C++ administrado. Visual Studio creará una aplicación "Hola a todos" sencilla.
2. Asegúrese de que el proyecto hace referencia al menos al espacio de nombres System. Utilice la instrucción using namespace de los espacios de nombres System, System.IO y System.Collections de forma que no tenga que suministrar declaraciones de estos espacios de nombres más adelante en el código. Debe utilizar estas instrucciones antes que cualquier otra declaración.
using namespace System;
using namespace System::IO;
using namespace System::Collections;
3. Para abrir un archivo para lectura, puede crear una nueva instancia de un objeto StreamReader y pasar la ruta de acceso del archivo en el constructor.
StreamReader* objReader = new StreamReader("c:\\test.txt");
4. Necesitará una variable de cadena para almacenar cada línea del archivo a medida que lo procesa y, como va a agregar estas líneas a un ArrayList, debe declarar y crear también un objeto de ese tipo.
String *sLine = "";
ArrayList *arrText = new ArrayList();
5. Hay varias opciones para leer el archivo, incluyendo un método llamado ReadToEnd que lee todo el archivo de una vez, pero para este ejemplo puede utilizar el método ReadLine para mostrar el archivo de línea en línea. Al llegar al final del archivo, este método devuelve un valor nulo, lo que permite terminar el bucle. A medida que lee cada línea del archivo puede insertarla en el objeto ArrayList mediante el método Add de ArrayList.
sLine = objReader->ReadLine();
while (sLine != 0)
{
arrText->Add(sLine);
sLine = objReader->ReadLine();<BR/>
}
objReader->Close();
6. Por último, envíe a la consola el contenido del ArrayList recién llenado mediante un bucle "For Each".
for(int i = 0; i<arrText->Count; i++)
Console::WriteLine(arrText->Item[i]->ToString());
Console::ReadLine();
7. Guarde y ejecute el código, que mostrará el contenido del archivo en la consola.
Volver al principio
Lista completa de código
#using <mscorlib.dll>
using namespace System;
using namespace System::IO;
using namespace System::Collections;

#ifdef _UNICODE
int wmain(void)
#else
int main(void)
#endif
{
StreamReader* objReader = new StreamReader("c:\\test.txt");
String *sLine = "";
ArrayList *arrText = new ArrayList();

sLine = objReader->ReadLine();
while (sLine != 0)
{
arrText->Add(sLine);
sLine = objReader->ReadLine();
}
objReader->Close();

//Escribir el ArrayList en la consola.
for(int i = 0; i<arrText->Count; i++)
Console::WriteLine(arrText->Item[i]->ToString());
Console::ReadLine();
return 0;
}
Volver al principio
Errores
Hay varios aspectos que debe tener en cuenta cuando trabaje con E/S de archivos. Siempre que se tiene acceso a archivos existe la posibilidad de que el archivo que intenta leer o en el que intenta escribir no esté en el sistema o esté en uso. También leerá todo el archivo en memoria antes de procesarlo y puede darse el caso de que el archivo sea demasiado grande y no quepa en la memoria. O bien, quizás no tenga permisos de acceso al archivo. Cualquiera de estas situaciones hará que se provoque una excepción. Es conveniente proporcionar siempre un bloque "Try...Catch" para tratar estos problemas habituales.

Volver al principio
Referencias
Tutoriales del SDK de Microsoft .NET Framework
http://www.gotdotnet.com/quickstart
Para obtener más información general acerca de Visual C++ .NET, visite el siguiente grupo de noticias Usenet:
Grupos de noticias en castellano
Microsoft.public.dotnet.languages.vc (en inglés)
Visite el centro de soporte técnico de Visual C++ .NET en:
Visual C++ .NET (2002) Support Center
Volver al principio

archivos de texto. Archivos de acceso aleatorio binarios de longitud de registro constante, normalmente usados en bases de datos. Y también cualquier combinación menos corriente, como archivos secuenciales binarios de longitud de registro constante, etc

archivo binario y tipos de archivos

Archivos Binarios
Contiene códigos y caracteres los cuales sólo pueden ser utilizados para un tipo específico de software. Los más comunes son los archivos ejecutables, gráficos y documentos con formato.

· Binarios: están permitidos todos lo valores para cada byte. En estos archivos el final del fichero se detecta de otro modo, dependiendo del soporte y del sistema operativo. La mayoría de las veces se hace guardando la longitud del fichero. Cuando queramos almacenar valores enteros, o en coma flotante, o imágenes, etc, deberemos usar este tipo de archivos.

archivos secuenciales binarios de longitud de registro constante,
En cuanto a cómo se definen estas propiedades, hay dos casos. Si son binarios o de texto o de entrada, salida o entrada/salida, se define al abrir el fichero, mediante la función fopen en C o mediante el método open de fstream en C++.
La función open usa dos parámetros. El primero es el nombre del fichero que contiene el archivo. El segundo es em modo que es una cadena que indica el modo en que se abrirá el archivo: lectura o escritura, y el tipo de datos que contiene: de texto o binarios.
En C, los ficheros admiten seis modos en cuanto a la dirección del flujo de datos:
· r: sólo lectura. El fichero debe existir.
· w: se abre para escritura, se crea un fichero nuevo o se sobrescribe si ya existe.
· a: añadir, se abre para escritura, el cursor se situa al final del fichero. Si el fichero no existe, se crea.
· r+: lectura y escritura. El fichero debe existir.
· w+: lectura y escritura, se crea un fichero nuevo o se sobrescribe si ya existe.
· a+: añadir, lectura y escritura, el cursor se situa al final del fichero. Si el fichero no existe, se crea.
En cuanto a los valores permitidos para los bytes, se puede añadir otro carácter a la cadena de modo:
· t: modo texto. Normalmente es el modo por defecto. Se suele omitir.
· b: modo binario.
En ciertos sistemas operativos no existe esta distinción, y todos los ficheros son binarios.
En C++ es algo diferente, el constructor de las clases ifstream, ofstream y fstream admite los parámetros para abrir el fichero directamente, y también disponemos del método open, para poder crear el stream sin asociarlo con un fichero concreto y hacer esa asociación más tarde.
En cuanto al tipo de acceso, en C y C++ podemos clasificar los archivos según varias categorías:
5. Dependiendo de la dirección del flujo de datos:
· De entrada: los datos se leen por el programa desde el archivo.
· De salida: los datos se escriben por el programa hacia el archivo.
· De entrada/salida: los datos pueden se escritos o leídos.
6. Dependiendo del tipo de valores permitidos a cada byte:
· De texto: sólo están permitidos ciertos rangos de valores para cada byte. Algunos bytes tienen un significado especial, por ejemplo, el valor hexadecimal 0x1A marca el fin de fichero. Si abrimos un archivo en modo texto, no será posible leer más allá de un byte con ese valor, aunque el fichero sea más largo.
· Binarios: están permitidos todos lo valores para cada byte. En estos archivos el final del fichero se detecta de otro modo, dependiendo del soporte y del sistema operativo. La mayoría de las veces se hace guardando la longitud del fichero. Cuando queramos almacenar valores enteros, o en coma flotante, o imágenes, etc, deberemos usar este tipo de archivos.
7. Según el tipo de acceso:
· Archivos secuenciales: imitan el modo de acceso de los antiguos ficheros secuenciales almacenados en cintas magnéticas y
· Archivos de acceso aleatorio: permiten acceder a cualquier punto de ellos para realizar lecturas y/o escrituras.
8. Según la longitud de registro:
· Longitud variable: en realidad, en este tipo de archivos no tiene sentido hablar de longitud de registro, podemos considerar cada byte como un registro. También puede suceder que nuestra aplicación conozca el tipo y longitud de cada dato almacenado en el archivo, y lea o escriba los bytes necesarios en cada ocasión. Otro caso es cuando se usa una marca para el final de registro, por ejemplo, en ficheros de texto se usa el carácter de retorno de línea para eso. En estos casos cada registro es de longitud diferente.
· Longitud constante: en estos archivos los datos se almacenan en forma de registro de tamaño contante. En C usaremos estructuras para definir los registros. C dispone de funciones de librería adecuadas para manejar este tipo de ficheros.
· Mixtos: en ocasiones pueden crearse archivos que combinen los dos tipos de registros, por ejemplo, dBASE usa registros de longitud constante, pero añade un registro especial de cabecera al principio para definir, entre otras cosas, el tamaño y el tipo de los registros.
Es posible crear archivos combinando cada una de estas categorías, por ejemplo: archivos secuenciales de texto de longitud de registro variable, que son los típicos archivos de texto. Archivos de acceso aleatorio binarios de longitud de registro constante, normalmente usados en bases de datos. Y también cualquier combinación menos corriente, como archivos secuenciales binarios de longitud de registro constante, etc.
En cuanto a cómo se definen estas propiedades, hay dos casos. Si son binarios o de texto o de entrada, salida o entrada/salida, se define al abrir el fichero, mediante la función fopen en C o mediante el método open de fstream en C++.
La función open usa dos parámetros. El primero es el nombre del fichero que contiene el archivo. El segundo es em modo que es una cadena que indica el modo en que se abrirá el archivo: lectura o escritura, y el tipo de datos que contiene: de texto o binarios.
En C, los ficheros admiten seis modos en cuanto a la dirección del flujo de datos:
· r: sólo lectura. El fichero debe existir.
· w: se abre para escritura, se crea un fichero nuevo o se sobrescribe si ya existe.
· a: añadir, se abre para escritura, el cursor se situa al final del fichero. Si el fichero no existe, se crea.
· r+: lectura y escritura. El fichero debe existir.
· w+: lectura y escritura, se crea un fichero nuevo o se sobrescribe si ya existe.
· a+: añadir, lectura y escritura, el cursor se situa al final del fichero. Si el fichero no existe, se crea.
En cuanto a los valores permitidos para los bytes, se puede añadir otro carácter a la cadena de modo:
· t: modo texto. Normalmente es el modo por defecto. Se suele omitir.
· b: modo binario.
En ciertos sistemas operativos no existe esta distinción, y todos los ficheros son binarios.
En C++ es algo diferente, el constructor de las clases ifstream, ofstream y fstream admite los parámetros para abrir el fichero directamente, y también disponemos del método open, para poder crear el stream sin asociarlo con un fichero concreto y hacer esa asociación más tarde.

2 Tipos, funciones y clases usados frecuentemente con ficheros
Funciones y tipos C estándar: inicioinicio
Tipo FILE:
C define la estructura de datos FILE en el fichero de cabecesa "stdio.h" para el manejo de ficheros. Nosotros siempre usaremos punteros a estas estructuras.
La definición de ésta estructura depende del compilador, pero en general mantienen un campo con la posición actual de lectura/escritura, un buffer para mejorar las prestaciones de acceso al fichero y algunos campos para uso interno.
Función fopen:
Sintaxis:
FILE *fopen(char *nombre, char *modo);
ésta función sirve para abrir y crear ficheros en disco. El valor de retorno es un puntero a una estructura FILE. Los parámetros de entrada son:
9. nombre: una cadena que contiene un nombre de fichero válido, esto depende del sistema operativo que estemos usando. El nombre puede incluir el camino completo.
10. modo: especifica en tipo de fichero que se abrirá o se creará y el tipo de datos que puede contener, de texto o binarios:
· r: sólo lectura. El fichero debe existir.
· w: se abre para escritura, se crea un fichero nuevo o se sobreescribe si ya existe.
· a: añadir, se abre para escritura, el cursor se situa al final del fichero. Si el fichero no existe, se crea.
· r+: lectura y escritura. El fichero debe existir.
· w+: lectura y escritura, se crea un fichero nuevo o se sobreescribe si ya existe.
· a+: añadir, lectura y escritura, el cursor se situa al final del fichero. Si el fichero no existe, se crea.
· t: tipo texto, si no se especifica "t" ni "b", se asume por defecto que es "t"
· b: tipo binario.
Función fclose:
Sintaxis:
int fclose(FILE *fichero);
Es importante cerrar los ficheros abiertos antes de abandonar la aplicación. Esta función sirve para eso. Cerrar un fichero almacena los datos que aún están en el buffer de memoria, y actualiza algunos datos de la cabecera del fichero que mantiene el sistema operativo. Además permite que otros programas puedan abrir el fichero para su uso. Muy a menudo, los ficheros no pueden ser compartidos por varios programas.
Un valor de retorno cero indica que el fichero ha sido correctamente cerrado, si ha habido algún error, el valor de retorno es la constante EOF. El parámetro es un puntero a la estructura FILE del fichero que queremos cerrar.
Función fgetc:
Sintaxis:
int fgetc(FILE *fichero);
Esta función lee un carácter desde un fichero.
El valor de retorno es el carácter leído como un unsigned char convertido a int. Si no hay ningún carácter disponible, el valor de retorno es EOF. El parámetro es un puntero a una estructura FILE del fichero del que se hará la lectura.
Función fputc:
Sintaxis:
int fputc(int caracter, FILE *fichero);
Esta función escribe un carácter a un fichero.
El valor de retorno es el carácter escrito, si la operación fue completada con éxito, en caso contrario será EOF. Los parámetros de entrada son el carácter a escribir, convertido a int y un puntero a una estructura FILE del fichero en el que se hará la escritura.
Función feof:
Sintaxis:
int feof(FILE *fichero);
Esta función sirve para comprobar si se ha alcanzado el final del fichero. Muy frecuentemente deberemos trabajar con todos los valores almacenados en un archivo de forma secuencial, la forma que suelen tener los bucles para leer todos los datos de un archivo es permanecer leyendo mientras no se detecte el fin de fichero. Esta función suele usarse como prueba para verificar si se ha alcanzado o no ese punto.
El valor de retorno es distinto de cero sólo si no se ha alcanzado el fin de fichero. El parámetro es un puntero a la estructura FILE del fichero que queremos verificar.
Función rewind:
Sintaxis:
void rewind(FILE *fichero)
Es una función heredada de los tiempos de las cintas magnéticas. Literalmente significa "rebobinar", y hace referencia a que para volver al principio de un archivo almacenado en cinta, había que rebobinarla. Eso es lo que hace ésta función, sitúa el cursor de lectura/escritura al principio del archivo.
El parámetro es un puntero a la estructura FILE del fichero que queremos rebobinar.
Ejemplos:
// ejemplo1.c: Muestra un fichero dos veces.
#include <stdio.h>

int main()
{
FILE *fichero;

fichero = fopen("ejemplo1.c", "r");
while(!feof(fichero)) fputc(fgetc(fichero), stdout);
rewind(fichero);
while(!feof(fichero)) fputc(fgetc(fichero), stdout);
fclose(fichero);
getchar();
return 0;
}
Función fgets:
Sintaxis:
char *fgets(char *cadena, int n, FILE *fichero);
Esta función está diseñada para leer cadenas de caracteres. Leerá hasta n-1 caracteres o hasta que lea un retorno de línea. En este último caso, el carácter de retorno de línea también es leído.
El parámetro n nos permite limitar la lectura para evitar derbordar el espacio disponible en la cadena.
El valor de retorno es un puntero a la cadena leída, si se leyó con éxito, y es NULL si se detecta el final del fichero o si hay un error. Los parámetros son: la cadena a leer, el número de caracteres máximo a leer y un puntero a una estructura FILE del fichero del que se leerá.
Función fputs:
Sintaxis:
int fputs(const char *cadena, FILE *stream);
La función fputs escribe una cadena en un fichero. No se añade el carácter de retorno de línea ni el carácter nulo final.
El valor de retorno es un número no negativo o EOF en caso de error. Los parámetros de entrada son la cadena a escribir y un puntero a la estructura FILE del fichero donde se realizará la escritura.
Función fread:
Sintaxis:
size_t fread(void *puntero, size_t tamaño, size_t nregistros, FILE *fichero);
Esta función está pensada para trabajar con registros de longitud constante. Es capaz de leer desde un fichero uno o varios registros de la misma longitud y a partir de una dirección de memoria determinada. El usuario es responsable de asegurarse de que hay espacio suficiente para contener la información leída.
El valor de retorno es el número de registros leídos, no el número de bytes. Los parámetros son: un puntero a la zona de memoria donde se almacenarán los datos leídos, el tamaño de cada registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la lectura.
Función fwrite:
Sintaxis:
size_t fwrite(void *puntero, size_t tamaño, size_t nregistros, FILE *fichero);
Esta función también está pensada para trabajar con registros de longitud constante y forma pareja con fread. Es capaz de escribir hacia un fichero uno o varios registros de la misma longitud almacenados a partir de una dirección de memoria determinada.
El valor de retorno es el número de registros escritos, no el número de bytes. Los parámetros son: un puntero a la zona de mmemoria donde se almacenarán los datos leídos, el tamaño de cada registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la lectura.
Ejemplo:
// copia.c: Copia de ficheros
// Uso: copia <fichero_origen> <fichero_destino>

#include <stdio.h>

int main(int argc, char **argv) {
FILE *fe, *fs;
unsigned char buffer[2048]; // Buffer de 2 Kbytes
int bytesLeidos;

if(argc != 3) {
printf("Usar: copia <fichero_origen> <fichero_destino>\n");
return 1;
}

// Abrir el fichero de entrada en lectura y binario
fe = fopen(argv[1], "rb");
if(!fe) {
printf("El fichero %s no existe o no puede ser abierto.\n", argv[1]);
return 1;
}
// Crear o sobreescribir el fichero de salida en binario
fs = fopen(argv[2], "wb");
if(!fs) {
printf("El fichero %s no puede ser creado.\n", argv[2]);
fclose(fe);
return 1;
}
// Bucle de copia:
while((bytesLeidos = fread(buffer, 1, 2048, fe)))
fwrite(buffer, 1, bytesLeidos, fs);
// Cerrar ficheros:
fclose(fe);
fclose(fs);
return 0;
}
Función fprintf:
Sintaxis:
int fprintf(FILE *fichero, const char *formato, ...);
La función fprintf funciona igual que printf en cuanto a parámetros, pero la salida se dirige a un fichero en lugar de a la pantalla.
Función fscanf:
Sintaxis:
int fscanf(FILE *fichero, const char *formato, ...);
La función fscanf funciona igual que scanf en cuanto a parámetros, pero la entrada se toma de un fichero en lugar del teclado.
Función fflush:
Sintaxis:
int fflush(FILE *fichero);
Esta función fuerza la salida de los datos acumulados en el buffer de salida del fichero. Para mejorar las prestaciones del manejo de ficheros se utilizan buffers, almacenes temporales de datos en memoria, las operaciones de salida se hacen a través del buffer, y sólo cuando el buffer se llena se realiza la escritura en el disco y se vacía el buffer. En ocasiones nos hace falta vaciar ese buffer de un modo manual, para eso sirve ésta función.
El valor de retorno es cero si la función se ejecutó con éxito, y EOF si hubo algún error. El parámetro de entrada es un puntero a la estructura FILE del fichero del que se quiere vaciar el buffer. Si es NULL se hará el vaciado de todos los ficheros abiertos.
Funciones C específicas para ficheros de acceso aleatorio inicioinicio
Función fseek:
Sintaxis:
int fseek(FILE *fichero, long int desplazamiento, int origen);
Esta función sirve para situar el cursor del fichero para leer o escribir en el lugar deseado.
El valor de retorno es cero si la función tuvo éxito, y un valor distinto de cero si hubo algún error.
Los parámetros de entrada son: un puntero a una estructura FILE del fichero en el que queremos cambiar el cursor de lectura/escritura, el valor del desplazamiento y el punto de origen desde el que se calculará el desplazamiento.
El parámetro origen puede tener tres posibles valores:
1. SEEK_SET el desplazamiento se cuenta desde el principio del fichero. El primer byte del fichero tiene un desplazamiento cero.
2. SEEK_CUR el desplazamiento se cuenta desde la posición actual del cursor.
3. SEEK_END el desplazamiento se cuenta desde el final del fichero.
Función ftell:
Sintaxis:
long int ftell(FILE *fichero);
La función ftell sirve para averiguar la posición actual del cursor de lectura/excritura de un fichero.
El valor de retorno será esa posición, o -1 si hay algún error.
El parámetro de entrada es un puntero a una estructura FILE del fichero del que queremos leer la posición del cursor de lectura/escritura.


3 Archivos secuenciales inicioinicio
En estos archivos, la información sólo puede leerse y escribirse empezando desde el principio del archivo.
Los archivos secuenciales tienen algunas características que hay que tener en cuenta:
11. La escritura de nuevos datos siempre se hace al final del archivo.
12. Para leer una zona concreta del archivo hay que avanzar siempre, si la zona está antes de la zona actual de lectura, será necesario "rebobinar" el archivo.
13. Los ficheros sólo se pueden abrir para lectura o para escritura, nunca de los dos modos a la vez.
Esto es en teoría, por supuesto, en realidad C no distingue si los archivos que usamos son secuenciales o no, es el tratamiento que hagamos de ellos lo que los clasifica como de uno u otro tipo.
Pero hay archivos que se comportan siempre como secuenciales, por ejemplo los ficheros de entrada y salida estándar: stdin, stdout, stderr y stdaux.
Tomemos el caso de stdin, que suele ser el teclado. Nuestro programa sólo podrá abrir ese fichero como de lectura, y sólo podrá leer los caracteres a medida que estén disponibles, y en el mismo orden en que fueron tecleados.
Lo mismo se aplica para stdout y stderr, que es la pantalla, en estos casos sólo se pueden usar para escritura, y el orden en que se muestra la información es el mismo en que se envía.
Un caso especial es stdaux, que suele ser el puerto serie. También es un archivo secuencial, con respecto al modo en que se leen y escriben los datos. Sin embargo se un fichero de entrada y salida.
Trabajar con archivos secuenciales tiene algunos inconvenientes. Por ejemplo, imagina que tienes un archivo de este tipo en una cinta magnética. Por las características físicas de este soporte, es eviente que sólo podemos tener un fichero abierto en cada unidad de cinta. Cada fichero puede ser leído, y también sobrescrito, pero en general, los archivos que haya a continuación del que escribimos se perderán, o bien serán sobreescritos al crecer el archivo, o quedará un espacio vacío entre el final del archivo y el principio del siguiente.
Lo normal cuando se quería actualizar el contenido de un archivo de cinta añadiendo o modificando datos, era abrir el archivo en modo lectura en una unidad de cinta, y crear un nuevo fichero de escritura en una unidad de cinta distinta. Los datos leídos de una cinta se editan o modifican, y se copian en la otra secuencialmente.
Cuando trabajemos con archivos secuenciales en disco haremos lo mismo, pero en ese caso no necesitamos dos unidades de disco, ya que en los discos es posible abrir varios archivos simultaneamente.
En cuanto a las ventajas, los archivos secuenciales son más sencillos de manejar, ya que requieren menos funciones, además son más rápidos, ya que no permiten moverse a lo largo del archivo, el punto de lectura y escritura está siempre determinado.
En ocasiones pueden ser útiles, por ejemplo, cuando sólo se quiere almacenar cierta información a medida que se recibe, y no interesa analizarla en el momento. Posteriormente, otro programa puede leer esa información desde el principio y analizarla. Este es el caso de archivos "log" o "diarios" por ejemplo, los servidores de las páginas WEB pueden generar una línea de texto cada vez que alguien accede al una de las páginas y las guardan en un fichero secuencial.
inicioinicioindex.php?cap=002index.php?cap=002index.php?cap=002index.php?cap=002index.php?cap=004" border=none height=24 src="imagen/pagsig.gif" width=24index.php?cap=004 index.php?cap=004" border=none height=24 src="imagen/capsig.gif" width=24index.php?cap=004


4 Archivos de acceso aleatorio inicioinicio
Los archivos de acceso aleatorio son más versátiles, permiten acceder a cualquier parte del fichero en cualquier momento, como si fueran arrays en memoria. Las operaciones de lectura y/o escritura pueden hacerse en cualquier punto del archivo.
En general se suelen establecer ciertas normas para la creación, aunque no todas son obligatorias:
14. Abrir el archivo en un modo que te permita leer y escribir. Esto no es imprescindible, es posible usar archivos de acceso aleatorio sólo de lectura o de escritura.
15. Abrirlo en modo binario, ya que algunos o todos los campos de la estructura pueden no ser caracteres.
16. Usar funciones como fread y fwrite, que permiten leer y escribir registros de longitud constante desde y hacia un fichero.
17. Usar la función fseek para situar el puntero de lectura/escritura en el lugar apropiado de tu archivo.
Por ejemplo, supongamos que nuestros registros tienen la siguiente estructura:
struct stRegistro {
char Nombre[34];
int dato;
int matriz[23];
} reg;
Teniendo en cuenta que los registros empiezan a contarse desde el cero, para hacer una lectura del registro número 6 usaremos:
fseek(fichero, 5*sizeof(stRegistro), SEEK_SET);
fread(&reg, sizeof(stRegistro), 1, fichero);
Análogamente, para hacer una operación de escritura, usaremos:
fseek(fichero, 5*sizeof(stRegistro), SEEK_SET);
fwrite(&reg, sizeof(stRegistro), 1, fichero);
Muy importante: después de cada operación de lectura o escritura, el cursor del fichero se actualiza automáticamente a la siguiente posición, así que es buena idea hacer siempre un fseek antes de un fread o un fwrite.
En el caso de streams, la forma de trabajar es análoga:
fichero.seekg(5*sizeof(stRegistro), ios::beg);
fichero.read(&reg, sizeof(stRegistro));
Y para hacer una operación de escritura, usaremos:
fichero.seekp(5*sizeof(stRegistro), ios::beg);
fichero.write(&reg, sizeof(stRegistro));
Calcular la longitud de un fichero
Para calcular el tamaño de un fichero, ya sea en bytes o en registros se suele usar el siguiente procedimiento:
long nRegistros;
long nBytes;
fseek(fichero, 0, SEEK_END); // Colocar el cursor al final del fichero
nBytes = ftell(fichero); // Tamaño en bytes
nRegistros = ftell(fich)/sizeof(stRegistro); // Tamaño en registros
En el caso de streams:
long nRegistros;
long nBytes;
fichero.seekg(0, ios::end); // Colocar el cursor al final del fichero
nBytes = fichero.tellg(); // Tamaño en bytes
nRegistros = fichero.tellg()/sizeof(stRegistro); // Tamaño en registros
Borrar registros
Borrar registros puede ser complicado, ya que no hay ninguna función de librería estándar que lo haga.
Es su lugar se suele usar uno de estos dos métodos:
4. Marcar el registro como borrado o no válido, para ello hay que añadir un campo extra en la estructura del registro:
struct stRegistro {
char Valido; // Campo que indica si el registro es válido
char Nombre[34];
int dato;
int matriz[23];
};
Si el campo Valido tiene un valor prefijado, por ejemplo 'S' o ' ', el registro es válido. Si tiene un valor prefijado, por ejemplo 'N' o '*', el registro será inválido o se considerará borrado.
De este modo, para borrar un registro sólo tienes que cambiar el valor de ese campo.
Pero hay que tener en cuenta que será el programa el encargado de tratar los registros del modo adecuado dependiendo del valor del campo Valido, el hecho de marcar un registro no lo borra físicamente.
Si se quiere elaborar más, se puede mantener un fichero auxiliar con la lista de los registros borrados. Esto tiene un doble propósito:
· Que se pueda diseñar una función para sustituir a fseek() de modo que se tengan en cuenta los registros marcados.
· Que al insertar nuevos registros, se puedan sobrescribir los anteriormente marcados como borrados, si existe alguno.
5. Hacer una copia del fichero en otro fichero, pero sin copiar el registro que se quiere borrar. Este sistema es más tedioso y lento, y requiere cerrar el fichero y borrarlo o renombrarlo, antes de poder usar de nuevo la versión con el registro eliminado.
Lo normal es hacer una combinación de ambos, durante la ejecución normal del programa se borran registros con el método de marcarlos, y cuando se cierra la aplicación, o se detecta que el porcentaje de registros borrados es alto o el usuario así lo decide, se "empaqueta" el fichero usando el segundo método.
Ejemplo:
A continuación se incluye un ejemplo de un programa que trabaja con registros de acceso aleatorio, es un poco largo, pero bastante completo:
// alea.c: Ejemplo de ficheros de acceso aleatorio.
#include <stdio.h>
#include <stdlib.h>

struct stRegistro {
char valido; // Campo que indica si el registro es válido S->Válido, N->Inválido
char nombre[34];
int dato[4];
};

int Menu();
void Leer(stRegistro &reg);
void Mostrar(stRegistro &reg);
void Listar(long n, stRegistro &reg);
long LeeNumero();
void Empaquetar(FILE *fa);

int main()
{
stRegistro reg;
FILE *fa;
int opcion;
long numero;

fa = fopen("alea.dat", "r+b"); // Este modo permite leer y escribir
if(!fa) fa = fopen("alea.dat", "w+b"); // si el fichero no existe, lo crea.

do {
opcion = Menu();
switch(opcion) {
case '1': // Añadir registro
Leer(reg);
// Insertar al final:
fseek(fa, 0, SEEK_END);
fwrite(&reg, sizeof(stRegistro), 1, fa);
break;
case '2': // Mostrar registro
system("cls");
printf("Mostrar registro: ");
numero = LeeNumero();
fseek(fa, numero*sizeof(stRegistro), SEEK_SET);
fread(&reg, sizeof(stRegistro), 1, fa);
Mostrar(reg);
break;
case '3': // Eliminar registro
system("cls");
printf("Eliminar registro: ");
numero = LeeNumero();
fseek(fa, numero*sizeof(stRegistro), SEEK_SET);
fread(&reg, sizeof(stRegistro), 1, fa);
reg.valido = 'N';
fseek(fa, numero*sizeof(stRegistro), SEEK_SET);
fwrite(&reg, sizeof(stRegistro), 1, fa);
break;
case '4': // Mostrar todo
rewind(fa);
numero = 0;
system("cls");
printf("Nombre Datos\n");
while(fread(&reg, sizeof(stRegistro), 1, fa)) Listar(numero++, reg);
system("PAUSE");
break;
case '5': // Eliminar marcados
Empaquetar(fa);
break;
}
} while(opcion != '0');
fclose(fa);
return 0;
}

// Muestra un menú con las opciones disponibles y captura una opción del usuario
int Menu()
{
char resp[20];

do {
system("cls");
printf("MENU PRINCIPAL\n");
printf("--------------\n\n");
printf("1- Insertar registro\n");
printf("2- Mostrar registro\n");
printf("3- Eliminar registro\n");
printf("4- Mostrar todo\n");
printf("5- Eliminar registros marcados\n");
printf("0- Salir\n");
fgets(resp, 20, stdin);
} while(resp[0] < '0' && resp[0] > '5');
return resp[0];
}

// Permite que el usuario introduzca un registro por pantalla
void Leer(stRegistro &reg)
{
int i;
char numero[6];

system("cls");
printf("Leer registro:\n\n");
reg.valido = 'S';
printf("Nombre: ");
fgets(reg.nombre, 34, stdin);
// la función fgets captura el retorno de línea, hay que eliminarlo:
for(i = strlen(reg.nombre)-1; i && reg.nombre[i] < ' '; i--) reg.nombre[i] = 0;
for(i = 0; i < 4; i++) {
printf("Dato[%1d]: ", i);
fgets(numero, 6, stdin);
reg.dato[i] = atoi(numero);
}
}

// Muestra un registro en pantalla, si no está marcado como borrado
void Mostrar(stRegistro &reg)
{
int i;

system("cls");
if(reg.valido == 'S') {
printf("Nombre: %s\n", reg.nombre);
for(i = 0; i < 4; i++) printf("Dato[%1d]: %d\n", i, reg.dato[i]);
}
system("PAUSE");
}

// Muestra un registro por pantalla en forma de listado,
// si no está marcado como borrado
void Listar(long n, stRegistro &reg)
{
int i;

if(reg.valido == 'S') {
printf("[%6ld] %-34s", n, reg.nombre);
for(i = 0; i < 4; i++) printf(", %4d", reg.dato[i]);
printf("\n");
}
}

// Lee un número suministrado por el usuario
long LeeNumero()
{
char numero[6];

fgets(numero, 6, stdin);
return atoi(numero);
}

// Elimina los registros marcados como borrados
void Empaquetar(FILE *fa)
{
FILE *ftemp;
stRegistro reg;

ftemp = fopen("alea.tmp", "wb");
rewind(fa);
while(fread(&reg, sizeof(stRegistro), 1, fa))
if(reg.valido == 'S') fwrite(&reg, sizeof(stRegistro), 1, ftemp);
fclose(ftemp);
fclose(fa);
remove("alea.bak");
rename("alea.dat", "alea.bak");
rename("alea.tmp", "alea.dat");
fa = fopen("alea.dat", "r+b");
}
Y esto es un ejemplo equivalente en C++:
// alea.cpp: Ejemplo de ficheros de acceso aleatorio.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <cstring>
using namespace std;

// Funciones auxiliares:
int Menu();
long LeeNumero();

// Clase registro.
class Registro {
public:
Registro(char *n=NULL, int d1=0, int d2=0, int d3=0, int d4=0) : valido('S') {
if(n) strcpy(nombre, n); else strcpy(nombre, "");
dato[0] = d1;
dato[1] = d2;
dato[2] = d3;
dato[3] = d4;
}
void Leer();
void Mostrar();
void Listar(long n);

const bool Valido() { return valido == 'S'; }
const char *Nombre() { return nombre; }
private:
char valido; // Campo que indica si el registro es válido
// S->Válido, N->Inválido
char nombre[34];
int dato[4];
};

// Implementaciones de clase Registro:
// Permite que el usuario introduzca un registro por pantalla
void Registro::Leer() {
system("cls");
cout << "Leer registro:" << endl << endl;
valido = 'S';
cout << "Nombre: ";
cin.getline(nombre, 34);
for(int i = 0; i < 4; i++) {
cout << "Dato[" << i << "]: ";
dato[i] = LeeNumero();
}
}

// Muestra un registro en pantalla, si no está marcado como borrado
void Registro::Mostrar()
{
system("cls");
if(Valido()) {
cout << "Nombre: " << nombre << endl;
for(int i = 0; i < 4; i++)
cout << "Dato[" << i << "]: " << dato[i] << endl;
}
cout << "Pulsa una tecla";
cin.get();
}

// Muestra un registro por pantalla en forma de listado,
// si no está marcado como borrado
void Registro::Listar(long n) {
int i;

if(Valido()) {
cout << "[" << setw(6) << n << "] ";
cout << setw(34) << nombre;
for(i = 0; i < 4; i++)
cout << ", " << setw(4) << dato[i];
cout << endl;
}
}

// Clase Datos, almacena y trata los datos.
class Datos :public fstream {
public:
Datos() : fstream("alea.dat", ios::in | ios::out | ios::binary) {
if(!good()) {
open("alea.dat", ios::in | ios::out | ios::trunc | ios::binary);
cout << "fichero creado" << endl;
cin.get();
}
}
~Datos() {
Empaquetar();
}
void Guardar(Registro &reg);
bool Recupera(long n, Registro &reg);
void Borrar(long n);

private:
void Empaquetar();
};

// Implementación de la clase Datos.
void Datos::Guardar(Registro &reg) {
// Insertar al final:
clear();
seekg(0, ios::end);
write(reinterpret_cast<char *> (&reg), sizeof(Registro));
cout << reg.Nombre() << endl;
}

bool Datos::Recupera(long n, Registro &reg) {
clear();
seekg(n*sizeof(Registro), ios::beg);
read(reinterpret_cast<char *> (&reg), sizeof(Registro));
return gcount() > 0;
}

// Marca el registro como borrado:
void Datos::Borrar(long n) {
char marca;

clear();
marca = 'N';
seekg(n*sizeof(Registro), ios::beg);
write(&marca, 1);
}

// Elimina los registros marcados como borrados
void Datos::Empaquetar() {
ofstream ftemp("alea.tmp", ios::out);
Registro reg;

clear();
seekg(0, ios::beg);
do {
read(reinterpret_cast<char *> (&reg), sizeof(Registro));
cout << reg.Nombre() << endl;
if(gcount() > 0 && reg.Valido())
ftemp.write(reinterpret_cast<char *> (&reg), sizeof(Registro));
} while (gcount() > 0);
ftemp.close();
close();
remove("alea.bak");
rename("alea.dat", "alea.bak");
rename("alea.tmp", "alea.dat");
open("alea.dat", ios::in | ios::out | ios::binary);
}

int main()
{
Registro reg;
Datos datos;
int opcion;
long numero;

do {
opcion = Menu();
switch(opcion) {
case '1': // Añadir registro
reg.Leer();
datos.Guardar(reg);
break;
case '2': // Mostrar registro
system("cls");
cout << "Mostrar registro: ";
numero = LeeNumero();
if(datos.Recupera(numero, reg))
reg.Mostrar();
break;
case '3': // Eliminar registro
system("cls");
cout << "Eliminar registro: ";
numero = LeeNumero();
datos.Borrar(numero);
break;
case '4': // Mostrar todo
numero = 0;
system("cls");
cout << "Nombre Datos" << endl;
while(datos.Recupera(numero, reg)) reg.Listar(numero++);
cout << "pulsa return";
cin.get();
break;
}
} while(opcion != '0');
return 0;
}

// Muestra un menú con las opciones disponibles y captura una opción del usuario
int Menu()
{
char resp[20];

do {
system("cls");
cout << "MENU PRINCIPAL" << endl;
cout << "--------------" << endl << endl;
cout << "1- Insertar registro" << endl;
cout << "2- Mostrar registro" << endl;
cout << "3- Eliminar registro" << endl;
cout << "4- Mostrar todo" << endl;
cout << "0- Salir" << endl;
cin.getline(resp, 20);
} while(resp[0] < '0' && resp[0] > '4');
return resp[0];
}

// Lee un número suministrado por el usuario
long LeeNumero()
{
char numero[6];

fgets(numero, 6, stdin);
return atoi(numero);
}


binarios
· Las componentes de un archivo de texto son de tipo char y están organizados en líneas.
· Sin embargo, las componentes de un archivo pueden ser de cualquier tipo predefinido o definido por el usuario excepto de tipo archivo.
· Una declaración general de archivos tiene la siguiente sintaxis:

FILE OF( tipo-componente )

donde FILE y OF son palabras reservadas, y tipo-componente puede ser cualquier tipo excepto otro tipo archivo.
Ejemplo:
TYPE
DiasDeSemana = ( Lunes, Martes, Miercoles, Jueves,
Viernes, Sabado, Domingo );
TipoCadena = PACKED ARRAY[1..20] OF char;
Lista = ARRAY[1..100] OF integer;
RegistroEmpleado = RECORD
Nombre : TipoCadena;
Numero, Dependientes : integer;
SueldoHora : real
END;
ArchivoDeNumeros = FILE OF integer;
ArchivoDeDias = FILE OF DiasDeSemana;
ArchivoCadenasLargas = FILES OF PACKED ARRAY[1..80] OF char;
ArchivoDeListas = FILE OF Lista;
ArchivoEmpleados = FILE OF RegistroEmpleado;

VAR
ArchConjuntoCaracteres : text;
ArchivoNumeros : ArchivoDeNumeros;
ArchivoDias : ArchivoDeDias;
ArchivoDirecciones : ArchivoCadenasLargas;
ArchivoLista : ArchivoDeListas;
ArchEmpleados : ArchivoEmpleados;
· Normalmente, los archivos binarios los puede crear únicamente el programa, y al acceso a las componentes de tales archivos es posible sólo dentro del programa.
· La información en un archivo binario es ilegible porque está utilizando un esquema de representación binario interno, que depende de la computadora que se use, y esta representación no se puede mostrar correctamente en forma de caracteres en un dispositivo de salida.
· La información en los archivos binarios se puede transferir más rápidamente entre la memoria principal y la memoria secundaria, y los elementos se almacenan de forma más compacta.

Escritura en un archivo binario
· Antes de poder escribir en un archivo (excepto output) se debe abrir para escritura utilizando el procedimiento rewrite, con la sintaxis:

rewrite( variable-archivo )
· Los valores se pueden escribir en un archivo utilizando el procedimiento write, con la sintaxis:

write( variable-archivo, lista-escritura )

donde lista-escritura es una expresión o una lista de expresiones separadas por comas, cada una de las cuales debe ser compatible con el tipo de las componentes de variable-archivo.
· Las componentes de un archivo de texto son de tipo char. Cuando se escribe en un archivo de texto otro tipo permitido --integer, real, boolean, cadenas-- se convierte en la cadena de caracteres apropiada y, estos caracteres, se escriben en el archivo. En el caso del procedimiento writeln a esta cadena le sigue un carácter de fin de línea.
Programa Una empresa necesita un archivo de registros de usuarios de una computadora. Crear un archivo de datos que contenga estos registros, uno para cada usuario. Cada registro debe contener el número de identificación del usuario, el sistema de la computadora (A, B, C o D) que usa, el límite de recursos para ese usuario y la cantidad de recursos utilizados hasta la fecha.
PROGRAM CreacionArchivoUsuarios( input, output, ArchUsuarios );
{********************************************************************

Entrada (teclado): Valores para los campos de un registro de tipo
RegistroUsuario.
Objetivo: Crear archivo binario ArchUsuarios cuyas
componentes son registros de tipo
RegistroUsuario. El usuario introduce los
campos de un registro RegUsuario durante la
ejecucion, y se utilza el procedimiento write
para escribir RegUsuario en ArchUsuarios.
Salida (archivo): El archivo binario ArchUsuarios.
Salida (pantalla): Mensajes al usuario y un mensaje sennalando
que la creacion del archivo se ha completado.

********************************************************************}

memoria donde se almacenarán los datos leídos, el tamaño de cada registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la lectura.
Ejemplo:
// copia.c: Copia de ficheros
// Uso: copia <fichero_origen> <fichero_destino>

#include <stdio.h>

int main(int argc, char **argv) {
FILE *fe, *fs;
unsigned char buffer[2048]; // Buffer de 2 Kbytes
int bytesLeidos;

if(argc != 3) {
printf("Usar: copia <fichero_origen> <fichero_destino>\n");
return 1;
}

// Abrir el fichero de entrada en lectura y binario
fe = fopen(argv[1], "rb");
if(!fe) {
printf("El fichero %s no existe o no puede ser abierto.\n", argv[1]);
return 1;
}
// Crear o sobreescribir el fichero de salida en binario
fs = fopen(argv[2], "wb");
if(!fs) {
printf("El fichero %s no puede ser creado.\n", argv[2]);
fclose(fe);
return 1;
}
// Bucle de copia:
while((bytesLeidos = fread(buffer, 1, 2048, fe)))
fwrite(buffer, 1, bytesLeidos, fs);
// Cerrar ficheros:
fclose(fe);
fclose(fs);
return 0;
}
Función fprintf:
Sintaxis:
int fprintf(FILE *fichero, const char *formato, ...);
La función fprintf funciona igual que printf en cuanto a parámetros, pero la salida se dirige a un fichero en lugar de a la pantalla.
Función fscanf:
Sintaxis:
int fscanf(FILE *fichero, const char *formato, ...);
La función fscanf funciona igual que scanf en cuanto a parámetros, pero la entrada se toma de un fichero en lugar del teclado.
Función fflush:
Sintaxis:
int fflush(FILE *fichero);
Esta función fuerza la salida de los datos acumulados en el buffer de salida del fichero. Para mejorar las prestaciones del manejo de ficheros se utilizan buffers, almacenes temporales de datos en memoria, las operaciones de salida se hacen a través del buffer, y sólo cuando el buffer se llena se realiza la escritura en el disco y se vacía el buffer. En ocasiones nos hace falta vaciar ese buffer de un modo manual, para eso sirve ésta función.
El valor de retorno es cero si la función se ejecutó con éxito, y EOF si hubo algún error. El parámetro de entrada es un puntero a la estructura FILE del fichero del que se quiere vaciar el buffer. Si es NULL se hará el vaciado de todos los ficheros abiertos.
Funciones C específicas para ficheros de acceso aleatorio inicioinicio
Función fseek:
Sintaxis:
int fseek(FILE *fichero, long int desplazamiento, int origen);
Esta función sirve para situar el cursor del fichero para leer o escribir en el lugar deseado.
El valor de retorno es cero si la función tuvo éxito, y un valor distinto de cero si hubo algún error.
Los parámetros de entrada son: un puntero a una estructura FILE del fichero en el que queremos cambiar el cursor de lectura/escritura, el valor del desplazamiento y el punto de origen desde el que se calculará el desplazamiento.
El parámetro origen puede tener tres posibles valores:
1. SEEK_SET el desplazamiento se cuenta desde el principio del fichero. El primer byte del fichero tiene un desplazamiento cero.
2. SEEK_CUR el desplazamiento se cuenta desde la posición actual del cursor.
3. SEEK_END el desplazamiento se cuenta desde el final del fichero.
Función ftell:
Sintaxis:
long int ftell(FILE *fichero);
La función ftell sirve para averiguar la posición actual del cursor de lectura/excritura de un fichero.
El valor de retorno será esa posición, o -1 si hay algún error.
El parámetro de entrada es un puntero a una estructura FILE del fichero del que queremos leer la posición del cursor de lectura/escritura.

 

algunos sitios de consulta sobre archivos de textos,binario

http://c.conclase.net/ficheros/index.php?cap=002

http://216.239.37.104/search?q=cache:iQoRmBd6gXYJ:www.dte.us.es/estadist/cc/PDF/practica_3.pdf+archivos+binarios&hl=es&lr=lang_es&ie=UTF-8

_http://216.239.53.104/search?q=cache:YIiMIW0YDVIJ:www.teclaredo.edu.mx/takeyas/Articulos/ARTICULO%2520Conceptos%2520basicos%2520de%

2520Administracion%2520de%2520Archivos.pdf+archivos+binarios&hl=es&lr=lang_es&ie=UTF-8

_http://216.239.39.104/search?q=cache:OGaLXxjLRj0J:bulma.net/pdf.phtml%3FnIdNoticia%3D664+archivos+binarios&hl=es&lr=lang_es&ie=UTF-8v

. http://66.102.7.104/search?q=cache:JywGC2if1q0J:www.teclaredo.edu.mx/takeyas/Materias/Administracion%2520de%2520Archivos/Manejo%

2520de%2520Archivos%2520en%2520Lenguaje%2520C%2B%2B/Manejo%2520de%2520Archivos%2520en%2520Lenguaje%2520C%2B%2B.

pdf+tipos+de+archivos+de+textos+c%2B%2B&hl=es&lr=lang_es&ie=UTF-8

 

 

Hosted by www.Geocities.ws

1