You are on page 1of 15

Archivos Binarios

Cuando se requiere efectuar operaciones con datos de alguno de los tipos primitivos, tales datos debern escribirse y leerse en formato binario. El espacio de nombres System.IO proporciona las clases: BinaryWriter y BinaryReader. Con estas clases se podrn manipular datos de los tipos primitivos y cadenas de caracteres en formato UTF-8. Los archivos escritos en formato binario no se pueden desplegar directamente en los dispositivos de salida estndar, como el monitor, sino que deben leerse a travs de flujos de la clase BinaryReader.

BinaryWriter crea flujos para escribir archivos con datos de los tipos primitivos en formato binario. Su constructor es: BinaryWriter ( Stream flujo ) y requiere, como parmetro, un flujo de la clase Stream o sus derivadas.

Ejemplo:
FileStream fs =new FileStream("datos.dat",FileMode. Create ,FileAccess. Write ); BinaryWriter bw=new BinaryWriter( fs ); Un objeto de la clase BinaryWriter acta como filtro entre el programa y un flujo de la clase FileStream. En la siguiente tabla se describen algunos de los principales mtodos y propiedades de la clase BinaryWriter : Mtodo / Propiedad Descripcin

Write(byte) Write(byte[]) Write(char) Write(char[]) Write(short) Write(int) Write(long) Write(Decimal) Write(float) Write(double) Write(string)

BaseStream Close Flush Seek

Escribe un valor de tipo byte. Escribe una cadena como una secuencia de bytes. Escribe un valor de tipo char. Escribe una cadena como una secuencia de caracteres. Escribe un valor de tipo short. Escribe un valor de tipo int. Escribe un valor de tipo long. Escribe un valor de tipo Decimal. Escribe un valor de tipo float. Escribe un valor de tipo double. Escribe una cadena de caracteres en formato UTF-8. El primero o los dos primeros bytes especifican el nmero de bytes de datos escritos en la cadena. Obtiene el flujo base ( fs en el ejemplo mostrado). Cierra el flujo y libera los recursos adquiridos. Limpia el buffer asociado con el flujo. Establece el apuntador de Lectura/Escritura en el flujo.

BinaryReader crea flujos para leer archivos con datos de los tipos primitivos en formato binario, escritos por un flujo de la clase Binaryreader. Su constructor es: BinaryReader ( Stream flujo ) y requiere, como parmetro, un flujo de la clase Stream o sus derivadas. Ejemplo: FileStream fs =new FileStream("datos.dat",FileMode. Open ,FileAccess. Read ); BinaryReader br=new BinaryReader( fs );

Un objeto de la clase BinaryReader acta como filtro entre un flujo de la clase FileStream y el programa. En la siguiente tabla se describen algunos de los principales mtodos y propiedades de la clase BinaryReader : Mtodo / Propiedad Read(byte) Read (byte[]) Read (char) Read (char[]) Read (short) Read (int) Read (long) Read (Decimal) Read (float) Read (double) Read (string) Descripcin Devuelve un valor de tipo byte. Devuelve una cadena como una secuencia de bytes. Devuelve un valor de tipo char. Devuelve una cadena como una secuencia de caracteres. Devuelve un valor de tipo short. Devuelve un valor de tipo int. Devuelve un valor de tipo long. Devuelve un valor de tipo Decimal. Devuelve un valor de tipo float. Devuelve un valor de tipo double. Devuelve una cadena de caracteres en formato UTF-8. El primero o los dos primeros bytes especifican el nmero de bytes de datos que sern ledos. Obtiene el flujo base ( fs en el ejemplo mostrado). Cierra el flujo y libera los recursos adquiridos. Limpia el buffer asociado con el flujo. Obtiene el siguiente carcter, sin extraerlo.

BaseStream Close Flush PeekChar

Acceso Aleatorio.
Cuando se abre un archivo, se puede acceder a sus registros de manera secuencial o de manera aleatoria . El acceso aleatorio consiste en posicionar el apuntador de archivo en una localidad especfica del archivo. Este tipo de acceso es necesario cuando se requiere modificar alguno de los campos de un registro. En

lugar de leer desde el primero hasta el registro elegido, el apuntador se posiciona ,en una especie de salto, hasta dicho registro. El salto se hace con base al conteo de los bytes existentes entre una posicin inicial y el primer byte del registro elegido. Para el acceso aleatorio a los registros de un archivo, la clase FileStream implementa las propiedades Position y Length , as como el mtodoSeek( ) Position devuelve la posicin actual, en bytes, del apuntador de archivo . El apuntador de archivo marca el byte donde se har la siguiente operacin de lectura o de escritura. La declaracin de la propiedad Position es: public long Position ; La propiedad Length devuelve la longitud del archivo en bytes. Est declarada as: public long Length ; El mtodo Seek( ) mueve el apuntador de archivo a una ubicacin localizada desp bytes, a partir de la posicin pos del archivo. La sintaxis para Seek( ) es: public long Seek( long desp , SeekOrigin pos ) El desplazamiento desp puede ser positivo o negativo. La posicin pos puede tomar uno de los siguientes valores del tipo enumerado SetOrigin .

Begin ........ El inicio del archivo. Current ..... Posicin actual del apuntador de archivo. End ........... El final del archivo.

Ejemplos: 1 .- Suponiendo un flujo fs de la clase FileStream . fs.Seek( desp , SeekOrigin. Begin ); fs.Seek( desp , SeekOrigin. Current ); fs.Seek( -desp , SeekOrigin. End ); El valor almacenado en desp debe calcularse en base al tamao de registro del archivo.

2 .- Suponiendo un flujo br de la clase BinaryReader .

FileStream fs = new FileStream("datos", FileMode.Open, FileAccess.Read);

BinaryReader br = new BinaryReader( fs );

Debido a que el flujo br no soporta directamente el mtodo Seek( ) , tiene que acceder a l a travs de su propiedad BaseStream , como se muestra a continuacin: br. BaseStream.Seek (desp, SeekOrigin.Current); Para facilitar el clculo del desplazamiento desp , es conveniente que todos los registros tengan la misma longitud.

En la figura anterior se muestra un archivo con 6 registros (numerados de 0 a 5) con 100 bytes de longitud cada uno. El desplazamiento para acceder al tercer registro se calcula de la siguiente manera: desp = Numero de registro * tamao de registro desp = 2*100 Es difcil recordar el nmero de registro al que se necesita acceder, por lo que se hace necesario establecer una relacin entre el nmero de registro y el valor almacenado en alguno de los campos del registro. Por ejemplo, si cada registro tiene un campo denominado clave , de tipo entero en el rango de 1 a N (que corresponde al nmero de control de un empleado), la relacin entre la clave y el nmero de registro es: nmero de registro = clave -1 As, el calculo del desplazamiento para el empleado con la clave 4 se efecta de la siguiente manera : desp = (4-1) * 100 = 300 Esto obliga a que, cuando se introduzcan los datos de un nuevo empleado , el nmero de su clave deba ser igual al nmero de registro +1 . El nmero de registro que sigue es igual al nmero de registros existentes.

Problema:
Una empresa necesita mantener una relacin con los datos: nombre, puesto y sueldo de cada uno de sus empleados.

Solucin:
Primero habr que disear una clase que contenga los atributos: nombre (cadena de 50 caracteres.)

puesto sueldo y los mtodos: asignaNombre( ) obtenNombre( ) asignaPuesto( ) obtenPuesto( ) asignaSueldo( ) obtenSueldo( ) tamao( )

(cadena de 20 caracteres.) (nmero de precisin sencilla.)

( asigna un valor a nombre) ( retorna el valor de nombre) ( asigna un valor a puesto) ( retorna el valor de puesto) ( asigna un valor a sueldo) ( retorna el valor de sueldo) ( retorna el nmero de bytes de un registro)

Con base a lo anterior, a continuacin definimos la clase Empleado : using System; using System.IO; public class Empleado { private string nombre; private string puesto; private float sueldo; public Empleado( ) { } public Empleado(string n, string p, float s) { nombre = n; puesto = p; sueldo = s; } public void asignaNombre( string n ) { nombre = n; } public string obtenNombre( ) {

return nombre; } public void asignaPuesto( string p ) { puesto = p; } public string obtenPuesto( ) { return puesto; } public void asignaSueldo( float s ) { sueldo = s; } public float obtenSueldo( ) { return sueldo; } }

Una vez definida la clase Empleado , definiremos la clase ArchivoEmpleados . public class ArchivoEmpleados { private FileStream fs ; // Flujo base. private BinaryWriter bw ; // Flujo de escritura. private BinaryReader br ; // Flujo de lectura.

public ushort nregs; // Nmero de registros en el archivo. public static ushort tamaoRegistro = 82 ; // Tamao del registro, en bytes. // Se agregan 2 bytes por cada string. public ushort c; public string n; public string p; public float s; public ArchivoEmpleados(string archivo) { fs = new FileStream (archivo, FileMode. OpenOrCreate , FileAccess. ReadWrite ); bw = new BinaryWriter ( fs ); br = new BinaryReader ( fs ); nregs=(ushort)Math.Ceiling((double)fs.Length /(double)tamaoRegistro); } public void cierraArchivo( ) { bw.Close ( ); br.Close ( ); fs.Close ( ); } public ushort obtnNmeroDeRegistros( ) { return nregs; } public void escribeRegistro(ushort clave, Empleado empleado) { if( clave > 0 && clave <= (nregs+1)) {

bw.BaseStream.Seek((clave-1)*tamaoRegistro, SeekOrigin.Begin); bw. Write (empleado. obtenNombre ( )); bw. Write (empleado. obtenPuesto ( )); bw. Write (empleado. obtenSueldo ( )); } else { Console.WriteLine("Clave incorrecta...."); } } public void captura( ) { Console.Write("Nombre: "); n =Console.ReadLine( ); n = n.PadRight(50) ; Console.Write("Puesto : "); p =Console.ReadLine( ); p = p.PadRight(20) ; Console.Write("Sueldo : "); s =Single.Parse(Console.ReadLine( )); } public void aadeRegistro(Empleado empleado) { nregs++; bw.BaseStream.Seek(nregs*tamaoRegistro, SeekOrigin.Begin); captura( ); escribeRegistro(nregs, new Empleado(n,p,s)); } public Empleado leeRegistro( ushort reg) { if(reg >= 0 && reg < nregs) { br.BaseStream.Seek(reg*tamaoRegistro, SeekOrigin.Begin); n = br.ReadString ( ); p = br.ReadString ( );

s = br.ReadSingle ( ); return new Empleado(n, p, s); } else { Console.WriteLine("Clave incorrecta...."); return null; } } public void buscaRegistro( ) { do{ Console.Write("Clave: "); c = UInt16.Parse(Console.ReadLine( )); }while(c< 1 && c> nregs); br.BaseStream.Seek((c-1)*tamaoRegistro, SeekOrigin.Begin); n = br.ReadString ( ); n = n.TrimEnd (' '); p = br.ReadString ( ); p = p.TrimEnd (' '); s = br.ReadSingle ( ); Console.Write("\nClave: " + c ); Console.Write("\nNombre: " + n ); Console.Write("\nPuesto: " + p ); Console.Write("\nSueldo: {0:F2}", s ); br.BaseStream.Seek((c-1)*tamaoRegistro, SeekOrigin.Begin); } public void cambiaRegistro( ) { buscaRegistro( ); Console.Write("\n Desea cambiarlo ( S/N) ? : "); char op; do {

op = (char) Console.Read( ); op = Char.ToUpper(op); } while(op != 'N' && op != 'S'); Console.ReadLine(); if( op == 'S') { captura( ) ; Empleado e=new Empleado(n,p,s); escribeRegistro((ushort)(c), e); } } public void despliegaRegistros( ) { for(int i = 0; br.BaseStream.Length != br.BaseStream.Position ; i++) { br.BaseStream.Seek(i*tamaoRegistro, SeekOrigin.Begin); n = br.ReadString( ); n = n.TrimEnd(' '); p = br.ReadString( ); p = p.TrimEnd(' '); s = br.ReadSingle( ); Console.Write("\n---------------------------\nClave: " + (i+1) ); Console.Write("\nNombre: " + n ); Console.Write("\nPuesto: " + p ); Console.Write("\nSueldo: {0:F2}", s ); } br.BaseStream.Seek(0, SeekOrigin.Begin); } public void eliminaRegistro( ) { buscaRegistro( ); Console.Write("\n Desea eliminarlo ( S/N) ? : "); char op; do {

op = (char) Console.Read( ); op = Char.ToUpper(op); } while(op != 'N' && op != 'S'); if( op == 'S') { n ="Registro eliminado"; n = n.PadRight(50); Empleado e=new Empleado(n,p,s); escribeRegistro(c, e); } } }

Con las clases Empleado y ArchivoEmpleados , vamos a definir la clase Principal que manejar el siguiente men: A .- Agregar. B .- Buscar. C .- Cambiar. D .- Desplegar. E .- Eliminar. S .- Salir. Opcin:

public class Principal { static ArchivoEmpleados arEmp; public static char men( ) { Console.Write("\n\n"); Console.WriteLine("A.- Agregar."); Console.WriteLine("B.- Buscar."); Console.WriteLine("C.- Cambiar.");

Console.WriteLine("D.- Desplegar."); Console.WriteLine("E.- Eliminar."); Console.WriteLine("S.- Salir."); Console.Write(" Opcin: "); char op; do { op = (char) Console.Read( ); op = Char.ToUpper(op); } while(op < 'A' || (op > 'E' && op != 'S')); Console.WriteLine( ); Console.ReadLine( ); return op; } public static void Main ( ) { string archivo = "Empleados.dat"; arEmp = new ArchivoEmpleados(archivo); char opcin; do { opcin = men( ); opcin = Char.ToUpper(opcin); switch(opcin) { case 'A': arEmp.aadeRegistro(new Empleado(arEmp.n,arEmp.p,arEmp.s)); break; case 'B': arEmp.buscaRegistro( ); break; case 'C': arEmp.cambiaRegistro( ); break; case 'D': arEmp.despliegaRegistros( );

break; case 'E': arEmp.eliminaRegistro( ); break; case 'S': arEmp.cierraArchivo(); break; } }while(opcin != 'S'); } }

You might also like