15 febrero 2012

Java para C# - 06 - Ficheros

Ahora vamos a ver un ejemplo de uso de ficheros en C#, que haga tres operaciones en ficheros:

  • Volcar de un fichero de texto a otro nuevo fichero de texto todas las líneas que cumplan una cierta condición (por ejemplo, comenzar por "A").
  • Contar las veces que aparece un cierto byte (como la letra "A") dentro de un fichero de cualquier tipo.
  • Copiar un fichero de cualquier tipo, usando bloques de 512 Kb de tamaño.

Podría ser así:

using System;
using System.IO;

class Ficheros
{
   
    public static void Main()
    {
        // Volcar a un fichero las líneas de otro (de texto)
        // que empiecen por "A"
        // Errores: sólo se comprueba si no existe el de origen
       
        StreamReader ficheroEntrada;
        StreamWriter ficheroSalida;
        string linea;
       
        if (! File.Exists("ejemplo.txt"))
        {
            Console.WriteLine("No encontrado ejemplo.txt");
            return;
        }
       
        Console.WriteLine("Copiando fichero de texto...");
       
        ficheroEntrada = File.OpenText("ejemplo.txt");
        ficheroSalida = File.CreateText("ejemplo2.txt");

        linea = ficheroEntrada.ReadLine();
        while (linea != null) {        
            if ((linea.Length > 1) && (linea[0] == 'A'))
                ficheroSalida.WriteLine(linea);
            linea = ficheroEntrada.ReadLine();
        }

        ficheroEntrada.Close();
        ficheroSalida.Close();
           
        // ----------------
        // Cantidad de "A" en un fichero de cualquier tipo
        // Mirando errores solo con try-catch
       
        Console.WriteLine("Contando A...");
        int contador = 0;
       
        try
        {
            BinaryReader ficheroEntrada2 =
                new BinaryReader(File.Open("ejemplo.exe", FileMode.Open));
            long tamanyo = ficheroEntrada2.BaseStream.Length;
            for(long i=0; i<tamanyo; i++)
                if (ficheroEntrada2.ReadByte() == Convert.ToByte('A'))
                    contador++;
            ficheroEntrada2.Close();
        }
        catch (Exception errorDeFichero)
        {
            Console.WriteLine(
                "Ha habido problemas: {0}",
                errorDeFichero.Message );
        }

        Console.WriteLine("Cantidad de A: " + contador);
       
        // ----------------
        // Copiar todo un fichero, con bloques de 512 Kb
        // Sin ninguna comprobación de errores
       
        Console.WriteLine("Copiando fichero binario...");
        const int BUFFER_SIZE = 512*1024;
       
        byte[] data = new byte[BUFFER_SIZE];
       
        FileStream ficheroEntrada3 = File.OpenRead("ejemplo.exe");
        FileStream ficheroSalida3 = File.Create("ejemplo2.exe");

        int cantidadLeida;
       
        do
        {
            cantidadLeida = ficheroEntrada3.Read(data,0,BUFFER_SIZE);
            ficheroSalida3.Write(data,0,cantidadLeida);
        }
        while (cantidadLeida == BUFFER_SIZE);
       
        ficheroEntrada3.Close();
        ficheroSalida3.Close();
        Console.WriteLine("Terminado!");
    }
  
}

Al convertir a Java, nos encontramos con unas cuantas diferencias:
  • Para comprobar si un fichero existe, la expresión es un poco más larga, porque hay que crear un objeto de tipo File.
  • Todas las operaciones de ficheros deben ir forzosamente encerradas en un bloque try-catch.
  • Los constructores para acceder a ficheros suelen ser más complicados que en C#. Por ejemplo, para leer un fichero de texto, se usa un BufferedReader, que se apoya en un FileReader, que a su vez se basa en un File que creamos a partir de un nombre de fichero.
  • El uso de ficheros de texto es básicamente igual: intentamos leer una línea, y obtendremos "null" si ya no se ha podido leer ninguna (el fichero ha terminado).
  • Para leer datos de tipo byte hasta el final de fichero, en vez de mirar el tamaño, podemos leer el dato y guardarlo dentro de un "int". Si el valor obtenido es -1, indica que no se ha podido leer (fin de fichero).
  • Para leer bloques y guardar bloques, podemos usar una construcción muy similar a la de C#, indicando el array, la posición y la cantidad de datos.
El resultado podría ser:

import java.io.*;

class Ficheros
{
   
    public static void main( String[] args )
    {
        // Volcar a un fichero las líneas de otro (de texto)
        // que empiecen por "A"
        // Errores: sólo se comprueba si no existe el de origen
               
        if (! (new File("ejemplo.txt")).exists() )
        {
            System.out.println("No encontrado ejemplo.txt");
            return;
        }
       
        System.out.println("Copiando fichero de texto...");
       
        try
        {
            BufferedReader ficheroEntrada = new BufferedReader(
                    new FileReader(new File("ejemplo.txt")));
            BufferedWriter ficheroSalida = new BufferedWriter(
                    new FileWriter(new File("ejemplo2.txt")));

            String linea=null;
            while ((linea=ficheroEntrada.readLine()) != null) {
                if ((linea.length() > 1) && (linea.charAt(0) == 'A'))
                {
                    ficheroSalida.write(linea);
                    ficheroSalida.newLine();
                }
            }

            ficheroEntrada.close();
            ficheroSalida.close();
        }
        catch (IOException errorDeFichero)
        {
            System.out.println(
                "Ha habido problemas: " +
                errorDeFichero.getMessage() );
        }
           
        // ----------------
        // Cantidad de "A" en un fichero de cualquier tipo
        // Mirando errores solo con try-catch
       
        System.out.println("Contando A...");
        int contador = 0;
       
        try
        {
            FileInputStream ficheroEntrada2 =
                new FileInputStream(new File("ejemplo.exe"));
           
            int dato;

            while ((dato = ficheroEntrada2.read()) != -1) {
               if (dato == 65) // Codigo ASCII de A
                    contador++;
            }
            ficheroEntrada2.close();
        }
        catch (Exception errorDeFichero)
        {
            System.out.println(
                "Ha habido problemas: " +
                errorDeFichero.getMessage() );
        }

        System.out.println("Cantidad de A: " + contador);
       
        // ----------------
        // Copiar todo un fichero, con bloques de 512 Kb
        // Sin ninguna comprobación de errores
       
        System.out.println("Copiando fichero binario...");
        final int BUFFER_SIZE = 512*1024;
       
        try
        {
            InputStream ficheroEntrada3 = new FileInputStream(
                    new File("ejemplo.exe"));
            OutputStream ficheroSalida3 = new FileOutputStream(
                    new File("ejemplo2.exe"));
           
            byte[] buf = new byte[BUFFER_SIZE];
            int cantidadLeida;
            while ((cantidadLeida = ficheroEntrada3.read(buf, 0, 
                    BUFFER_SIZE)) > 0) 
          {
                ficheroSalida3.write(buf, 0, cantidadLeida);
            }
            ficheroEntrada3.close();
            ficheroSalida3.close();
        }
        catch (Exception errorDeFichero)
        {
            System.out.println(
                "Ha habido problemas: " +
                errorDeFichero.getMessage() );
        }
  
        System.out.println("Terminado!");
    }
}

Como siempre, si tienes dudas, ya sabes: usa los comentarios o el foro de Java de AprendeAProgramar.