AnteriorPosterior

8.15. Escribir en un fichero binario

  Curso: Programación en C# (2015), por Nacho Cabanes

8.15. Escribir en un fichero binario

Para escribir en un FileStream, usaremos órdenes similares a las que empleábamos para leer de él:

  • Un método WriteByte, para escribir sólo un byte, o bien...
  • Un método Write, para escribir un bloque de información (desde cierta posición de un array -normalmente 0-, y con cierto tamaño).

Además, a la hora de abrir el fichero, tenemos dos alternativas:

  • Abrir un fichero existente con "OpenWrite".
  • Crear un nuevo fichero con "Create".

Vamos a ver un ejemplo que junte todo ello: crearemos un fichero, guardaremos datos, lo leeremos para comprobar que todo es correcto, añadiremos al final, y volveremos a leer:

?// Ejemplo_08_15a.cs
// Ficheros binarios: escritura en FileStream
// Introducción a C#, por Nacho Cabanes
 
using System;
using System.IO;
 
public class Ejemplo_08_15a
{
    const int TAMANYO_BUFFER = 10;
 
    public static void Main()
    {
        FileStream fichero;
        string nombre;
        byte[] datos;
 
        nombre = "datos.dat";
        datos = new byte[TAMANYO_BUFFER];
 
        // Damos valores iniciales al array
        for (byte i=0; i<TAMANYO_BUFFER; i++)
            datos[i] = (byte) (i + 10);
 
        try 
        {      
            // Primero creamos el fichero, con algun dato
            fichero = File.Create( nombre );
            fichero.Write(datos, 0, TAMANYO_BUFFER);
            fichero.Close();
 
            // Ahora leemos dos datos
            fichero = File.OpenRead(nombre);
            Console.WriteLine("El tamaño es {0}", fichero.Length);
            fichero.Seek(2, SeekOrigin.Begin);
            int nuevoDato = fichero.ReadByte();
            Console.WriteLine("El tercer byte es un {0}", nuevoDato);      
            fichero.Seek(-2, SeekOrigin.End);
            nuevoDato = fichero.ReadByte();
            Console.WriteLine("El penultimo byte es un {0}", nuevoDato);
            fichero.Close();
 
            // Ahora añadimos 10 datos más, al final
            fichero = File.OpenWrite(nombre);
            fichero.Seek(0, SeekOrigin.End);
            fichero.Write(datos, 0, TAMANYO_BUFFER);
            // y modificamos el tercer byte
            fichero.Seek(2, SeekOrigin.Begin);
            fichero.WriteByte( 99 );
            fichero.Close();
 
            // Volvemos a leer algun dato
            fichero = File.OpenRead(nombre);
            Console.WriteLine("El tamaño es {0}", fichero.Length);
            fichero.Seek(2, SeekOrigin.Begin);
            nuevoDato = fichero.ReadByte();
            Console.WriteLine("El tercer byte es un {0}", nuevoDato);
            fichero.Close();
 
        } 
        catch (Exception e)
        {
            Console.WriteLine("Problemas: "+e.Message);
            return;
        }
    }
}
 

(Nota: existe una propiedad "CanWrite" que nos permite saber si se puede escribir en el fichero).

Si queremos que escribir datos básicos de C# (float, int, etc.) en vez de un array de bytes, podemos usar un "BinaryWriter", que se maneja de forma similar a un "BinaryReader", con la diferencia de que no tenemos métodos WriteByte, WriteString y similares, sino un único método "Write", que se encarga de escribir el dato que le indiquemos, sea del tipo que sea:

?// Ejemplo_08_15b.cs
// Ficheros binarios: escritura en BinaryWriter
// Introducción a C#, por Nacho Cabanes
 
using System;
using System.IO;
 
public class Ejemplo_08_15b
{
    public static void Main()
    {
        BinaryWriter ficheroSalida;
        BinaryReader ficheroEntrada;
        string nombre;
 
        // Los datos que vamos a guardar/leer
        byte unDatoByte;
        int unDatoInt;
        float unDatoFloat;
        double unDatoDouble;
        string unDatoString;
 
        Console.Write("Introduzca el nombre del fichero a crear: ");
        nombre = Console.ReadLine();
 
        Console.WriteLine("Creando fichero...");
        // Primero vamos a grabar datos
        try 
        {      
            ficheroSalida = new BinaryWriter(
            File.Open(nombre, FileMode.Create));
            unDatoByte = 1;
            unDatoInt = 2;
            unDatoFloat = 3.0f;
            unDatoDouble = 4.0;
            unDatoString = "Hola";      
            ficheroSalida.Write(unDatoByte);
            ficheroSalida.Write(unDatoInt);
            ficheroSalida.Write(unDatoFloat);
            ficheroSalida.Write(unDatoDouble);
            ficheroSalida.Write(unDatoString);
            ficheroSalida.Close();    
        } 
        catch (Exception e)
        {
            Console.WriteLine("Problemas al crear: "+e.Message);
            return;
        }
 
        // Ahora vamos a leerlos
        Console.WriteLine("Leyendo fichero...");
        try 
        {
            ficheroEntrada = new BinaryReader(
            File.Open(nombre, FileMode.Open));
 
            unDatoByte = ficheroEntrada.ReadByte();
            Console.WriteLine("El byte leido es un {0}",
                unDatoByte);
 
            unDatoInt = ficheroEntrada.ReadInt32();
            Console.WriteLine("El int leido es un {0}",
                unDatoInt);
 
            unDatoFloat = ficheroEntrada.ReadSingle();
            Console.WriteLine("El float leido es un {0}",
                unDatoFloat);
 
            unDatoDouble = ficheroEntrada.ReadDouble();
            Console.WriteLine("El double leido es un {0}",
                unDatoDouble);
 
            unDatoString = ficheroEntrada.ReadString();
            Console.WriteLine("El string leido es \"{0}\"",
                unDatoString);
            Console.WriteLine("Volvamos a leer el int...");
 
            ficheroEntrada.BaseStream.Seek(1, SeekOrigin.Begin);
                unDatoInt = ficheroEntrada.ReadInt32();
            Console.WriteLine("El int leido es un {0}",
                unDatoInt);
            ficheroEntrada.Close();    
        } 
        catch (Exception e)
        {
            Console.WriteLine("Problemas al leer: "+e.Message);
            return;
        }
    }
}
 

El resultado de este programa es:

Introduzca el nombre del fichero a crear: 1234
Creando fichero...
Leyendo fichero...
El byte leido es un 1
El int leido es un 2
El float leido es un 3
El double leido es un 4
El string leido es "Hola"
Volvamos a leer el int...
El int leido es un 2
 

En este caso hemos usado "FileMode.Create" para indicar que queremos crear el fichero, en vez de abrir un fichero ya existente. Los modos de fichero que podemos emplear en un BinaryReader o en un BinaryWriter son los siguientes:

  • CreateNew: Crear un archivo nuevo. Si existe, se produce una excepción IOException.
  • Create: Crear un archivo nuevo. Si ya existe, se sobrescribirá.
  • Open: Abrir un archivo existente. Si el archivo no existe, se produce una excepción System.IO.FileNotFoundException.
  • OpenOrCreate: Se debe abrir un archivo si ya existe; en caso contrario, debe crearse uno nuevo.
  • Truncate: Abrir un archivo existente y truncarlo para que su tamaño sea de cero bytes.
  • Append: Abre el archivo si existe y se desplaza hasta el final del mismo, o crea un archivo nuevo si no existe.

Ejercicios propuestos:

Ejercicio propuesto 8.15.1: Crea una copia de un fichero EXE. La copia debe tener el mismo nombre y extensión BAK.
Ejercicio propuesto 8.15.2: Crea un programa que "encripte" el contenido de un fichero BMP, volcando su contenido a un nuevo fichero, en el que intercambiará los dos primeros bytes. Para desencriptar, bastará con volver a intercambiar esos dos bytes, volcando a un tercer fichero.

Actualizado el: 22-03-2015 17:08

AnteriorPosterior