viernes, 9 de octubre de 2015

Manejo de archivos en Java y C#

Elaboró: Alexis Romero Mendoza


Manejo de Archivos en los lenguajes de programación de alto nivel: Java y C#

Introducción

Las computadoras utilizan archivos para la retención a largo plazo de grandes cantidades de datos. Las personas utilizamos a diario archivos, en tareas como ensayos, hojas de cálculo, etc.

Sabemos que el almacenamiento de datos en variables o arreglos es temporal, pues se pierden generalmente cuando termina el programa. Nos vamos a referir a los datos que se mantienen en archivos como datos persistentes, ya que existen más allá de la duración de la ejecución del programa. Las computadoras almacenan los archivos en dispositivos de almacenamiento secundario como discos duros, discos ópticos, etc.

El procesamiento de archivos es una herramienta muy importante con la que debe de contar un lenguaje de programación para que pueda soportar aplicaciones comerciales que procesan cantidades masivas de datos persistentes.

Una computadora  procesa todo los elementos de datos como combinaciones de ceros y unos, los circuitos de las maquinas realizan varias manipulaciones simples de bits. Lo anterior resulta muy difícil, en vez de ello los programadores prefieren trabajar con datos en formatos como dígitos decimales. Los dígitos, letras y símbolos especiales se conocen como caracteres, el conjunto de caracteres de la computadora es el conjunto de todos los caracteres utilizados para escribir programas y representar elementos de datos. Las computadoras pueden  procesar  solamente 1s y 0s, un conjunto de caracteres ésta compuesto de bits, los campos están compuestos de caracteres o bytes, un campo es un grupo de caracteres o bytes que transmiten cierto significado, varios campos forman un registro, un archivo es un grupo de registros relacionados, un archivo puede verse como una colección de bytes.

Se hablara en esta investigación sobre el procesamiento de archivos (leer y escribir) mediante los lenguajes de programación Java y C#.


 1.-Manejo de archivos en Java

Java considera a cada archivo como un flujo secuencial de bytes.

1.1.-Archivos y flujos
Los flujos de archivos se pueden utilizar para la entrada y salida de datos, ya sea como caracteres o bytes. Los flujos que reciben y envían bytes a archivos se conocen como flujos basados en bytes, y almacenan datos en su formato binario. Los flujos que reciben y envían caracteres de/a los archivos se conocen como flujos basados en caracteres, y almacenan datos como una secuencia de caracteres.

Los archivos que se crean usando flujos basados en bytes se conocen como archivos binarios, mientras que los archivos que se crean usando flujos basados en caracteres se conocen como archivos de texto. Los archivos de texto se pueden leer con editores de texto, mientras que los archivos binarios se leen mediante un programa que convierte los datos en un formato que pueden leer los humanos.

Un programa de Java abre un archivo creando un objeto y asociándole un flujo de bytes o de caracteres. Los programas de Java realizan el procesamiento de archivos utilizando clases del paquete java.io. Este paquete incluye definiciones para las clases de flujo como FileInputStream (para la entrada basada en bytes desde un archivo), FileOutputStream (para la salida basada en bytes hacia un archivo), FileReader (para la entrada basada en caracteres desde un archivo) y FileWriter (para la salida basada en caracteres hacia un archivo). Los archivos se abren creando objetos de estas clases de flujos, que heredan de las clases InputStream, OutputStream, Reader y Writer.

La clase Scanner se utiliza en forma extensa para recibir datos del teclado. Como veremos, esta clase también puede leer datos de un archivo. La clase Formatter permite mostrar datos con formato en la pantalla, o enviarlos a un archivo, en forma similar a System.out.printf.

1.2.-La clase File

Los objetos de la clase File no abren archivos ni proporcionan herramientas para procesarlos. No obstante, los objetos File se utilizan frecuentemente con objetos de otras clases de java.io para especificar los archivos o directorios que van a manipularse.

Creación de objetos File
La clase File proporciona cuatro constructores.
1   1)   El constructor: public File( String nombre )
Especifica el nombre de un archivo o directorio que se asociará con el objeto File. El nombre puede contener información sobre la ruta, así como el nombre de un archivo o directorio.

2        2)  El constructor: public File( String rutaAlNombre, String nombre )
Usa el argumento rutaAlNombre (una ruta absoluta o relativa) para localizar el archivo o directorio especificado por nombre.

3       3)  El constructor: public File( File directorio, String nombre )
Usa un objeto File existente llamado directorio (una ruta absoluta o relativa) para localizar el archivo o directorio especificado por nombre.

      4) El constructor: public File( URI uri )
Usa el objeto URI dado para localizar el archivo. Un Identificador uniforme de recursos (URI) es una forma más general de un Localizador uniforme de recursos (URL), el cual se utiliza comúnmente para localizar sitios Web.

Puede utilizar la clase File para determinar muchas cosas sobre archivos, como su tamaño, si se puede escribir sobre ellos, si un elemento es un archivo, directorio o conexión de nombres,   más aún. Se puede utilizar isFile para determinar si un elemento es un archivo verdadero u otra cosa, como un directorio (lo puede comprobar con isDirectory) o una conexión de nombres. Utilice toURL para convertir la vía de acceso de un archivo a un URL, renombrar archivos y otros con la clase File.

Se puede utilizar uno de los siguientes métodos para reunir información sobre el archivo:
1)      Nombres de archivo:
    String getName()
  String getPath()
  String getAbsolutePath()
  String getParent()
  boolean renameTo( File nuevoNombre )



2)      Comprobaciones:
boolean exists()
boolean canWrite()
boolean canRead()
boolean isFile()
boolean isDirectory()
boolean isAbsolute()


3)     Información general del archivo:
long lastModified()
long length()

4)      Utilidades de directorio:
 boolean mkdir()
 String[] list()


1.3. - Las clases FIleInputStream y FileOutputStream

Gran parte de la entrada y salida de los programas se realiza basándose en archivos y para ello java.io aporta dos clases. Una para archivos de entrada, FileInputStream, y otra para archivos de salida, FileOutputStream. La diferencia entre archivos de entrada y de salida es fundamental, pues situaciones como intentar leer de un archivo de salida o viceversa pueden generar en errores.

1.2.1.-Apertura de un FileInputStream

Para abrir un FileInputStream sobre un archivo, se le da al constructor un String o un objeto File: El ejemplo siguiente crea dos FileInputStreams que están utilizando el mismo archivo de disco real. Cualquiera de los dos constructores disponibles en esta clase puede lanzar una FileNotFoundException.

InputStream f1 = new FileInputStream("/archivo.txt");
File f = new file("/archive.txt");
InputStream f2 = new FileInputStream(f);
FileInputStream fichero=new FileInputStream("/carpeta/archive.txt");
File fichero = new File( "/carpeta/archive.txt" );
FileInputStream ficheroSt= new FileInputStream( fichero );

Aunque probablemente el primer constructor es el que más se utiliza habitualmente, el segundo permite examinar el archivo más de cerca utilizando sus métodos antes de asignarlo a un flujo de entrada. Cuando se crea un FileInputStream, también se abre para lectura. FileInputStream sobrescribe seis de los métodos de la clase abstracta InputStream. Si se intentan utilizar los métodos mark o reset en un FileInputStream se generará una IOException.


1.2.2.-Lectura de un FileInputStream

Una vez abierto el FileInputStream, se puede leer de él. El método read() tiene muchas opciones:

1)      int read();
      Lee un byte y devuelve -1 al final del stream.

2)      int read( byte b[] );
Llena todo el array, si es posible. Devuelve el número de bytes leídos o -1 si se alcanzó el final del stream.

3)      int read( byte b[],int offset,int longitud );
Lee longitud bytes en b comenzando por b[offset]. Devuelve el número de bytes   leídos o -1 si se alcanzó el final del stream.

1.2.3.-Cierre de FileInputStream

Cuando se termina con un archivo, existen dos opciones para cerrarlo: explícitamente, o implícitamente cuando se recicla el objeto (el garbage collector se encarga de ello).

Para cerrarlo explícitamente, se utiliza el método close():
 miArchivoSt.close();

1.2.4.-Apertura de un FileOutputStream

Para abrir un objeto FileOutputStream, se tienen las mismas posibilidades que para abrir un archivo stream de entrada. Se le da al constructor un String o un objeto File.

FileOutputStream miArchivoSt;
miArchivoSt = new FileOutputStream( "/etc/kk" );

Como con los streams de entrada, también se puede utilizar:

File miArchivo FileOutputStream miArchivoSt;
miArchivo = new File( "/etc/kk" );
miArchivoSt = new FileOutputStream( miArchivo ); 


1.2.5.-Escritura en un FileOutputStream

Una vez abierto el archivo, se pueden escribir bytes de datos utilizando el método write().
Como con el método read() de los streams de entrada, tenemos tres posibilidades:

void write( int b );//Escribe un byte.

void write( byte b[] );//Escribe todo el array, si es posible.

void write( byte b[],int offset,int longitud );//Escribe longitud bytes en b comenzando por b[offset]

1.2.6.-Cierre de FileOutputStream

Cerrar un stream de salida es similar a cerrar streams de entrada. Se puede utilizar el método explícito: miArchivoSt.close();
O, se puede dejar que el sistema cierre el archivo cuando se recicle miArchivoSt.

2.-Manejo de archivos en C#


La manera de almacenar y recuperar información que perdure en el tiempo se basa en el uso de “memoria secundaria”, compuesta esencialmente por discos (diskettes, discos duros, CD, DVD, etc.) y ocasionalmente cintas. En cualquiera de estos medios, la unidad de almacenamiento de información se denomina archivo.

2.1.-Streams

La lectura y escritura a un archivo son hechas usando un concepto genérico llamado stream. La idea detrás del stream existe hace tiempo, cuando los datos son pensados como una transferencia de un punto a otro, es decir, como un flujo de datos. En el ambiente .NET se puede encontrar muchas clases que representan este concepto que trabaja con archivos o con datos de memoria.


Un stream es como se denomina a un objeto utilizado para transferir datos. Estos datos pueden ser transferidos en dos posibles direcciones:

1)       Si los datos son transferidos desde una fuente externa al programa, entonces se habla de “leer desde el stream”.

2)    Si los datos son transferidos desde el programa a alguna fuente externa, entonces se habla de “escribir al stream”.

Frecuentemente, la fuente externa será un archivo, pero eso no necesariamente es el caso, por lo que el concepto es utilizado ampliamente con fuentes de información externas de diversos tipos.

-Leer o escribir datos a una red utilizando algún protocolo de red, donde la intención es que estos datos sean recibidos o enviados por otro computador.

 -Lectura o escritura a un área de memoria., otros.

Algunas clases que C# provee para resolver este acceso a fuentes diversas incluyen las clases de tipo: Reader y Writer.

2.1.1.-BufferedStream

Esta clase se utiliza para leer y para escribir a otro stream. El uso de streams para la lectura y escritura de archivo es directa pero lenta. Para operaciones de archivo es posible utilizar FileStream, donde el buffering está ya incluido.

Las clases más relacionadas con la escritura y lectura de archivos (File Input/Output o File I/O) son:

1) FileStream, cuyo propósito es lectura y escritura de datos binarios (no de texto legible), a cualquier archivo de tipo binario, aunque se puede utilizar para acceder a cualquier tipo de archivo, inclusive los de texto.

2) StreamReader y StreamWriter, las cuales están diseñadas para lectura y escritura de archivos de texto. Estas clases se asumen como de un nivel más alto que FileStream.

En la declaración de nombres/rutas de archivos en C#. Se utiliza una sintaxis particular, anteponiendo el símbolo ‘@’ antes del string con la ruta del archivo. Es decir:

string rutaarchivo = @”C:\Temp\archivo.txt”;

2.2.-Using System.IO

Para el uso de estas clases, es necesario referenciar el uso del namespace System.IO, ya que System no contiene los elementos para el manejo de archivos. Por ello, los programas con acceso a archivos deben incluir la línea:

using System.IO;

2.2.1.-Constructor de StreamReader

El más simple de los constructores toma sólo el nombre/ruta del archivo a abrir para lectura:

StreamReader ob = new StreamReader(@”C:\Temp\archivo.txt”);

El constructor deja abierto el stream para poder recuperar la información del archivo desde la instancia de StreamReader declarada. Para cerrar un stream o archivo, se invoca el método Close():

ob.Close();

2.2.2.-Lectura con StreamReader

Son básicamente tres los métodos propios de StreamReader que permiten efectuar lectura desde el stream (archivo) declarado.

1)  ReadLine()
Al igual que el conocido Console.ReadLine(), este método lee una línea completa de un archivo de texto hasta el cambio de línea más próximo. Al igual que su equivalente de consola, StreamReader.ReadLine() no incluye en el string el carácter de cambio de línea.

string linea = ob.ReadLine()

2)  ReadToEnd()
Este método, por su parte, se encarga de acumular la información que hay desde la lectura anterior (que pudo haberse hecho con ReadLine(), por ejemplo) hasta el final del archivo, todo en el mismo string.

string linea = ob.ReadToEnd()

3)  Read ()
Finalmente, el método simple Read() se encarga de leer un caracter a la vez, lo que permite procesar símbolo por símbolo el contenido del archivo. Convenientemente, este método reconoce el cambio de línea y se lo salta como si no existiese. Cuando se encuentra con el fin de archivo, retorna un valor –1, considerando que su retorno es siempre un int (y no un char).

int SigCaracter = ob.Read();

Este mismo método ofrece una declaración alternativa (sobrecarga), donde es posible leer una cantidad específica de caracteres y almacenarlos en un arreglo de enteros.

char[] CharArray = new char[100];
int[] nChars = ob.Read(CharArray, 0, 100);

nChars es un arreglo con los enteros retornados por el método, y será menor si es que la cantidad de caracteres que quedan en el archivo es menor de 100.

2.2.3.- Escritura con StreamWriter

Esta clase funciona prácticamente de la misma manera que StreamReader, excepto que su propósito es únicamente para escribir dentro de un archivo (u otro stream). Es relevante distinguir que en este caso, el proceso de apertura para escritura considera que:

1)      Si el archivo no existe lo crea vacío para comenzar a escribir.
2)      Si el archivo ya existe, lo deja vacío para comenzar a escribir.
3)  Si el archivo ya existe, es posible abrirlo en forma “Append” (agregar) para escribir al final.

2.2.4.-Constructor de StreamWriter
El más simple de los constructores toma sólo el nombre/ruta del archivo a abrir para escritura.

StreamWriter sw = new StreamWriter (@”C:\Temp\archivo.txt”);

De la misma manera que en el caso de la lectura, para cerrar un stream o archivo, se invoca el método Close():

ob.Close();

2.2.5.- Escritura con StreamWriter

Son básicamente dos los métodos propios de StreamWriter que permiten escribir hacia el stream (archivo) declarado y son los mismos que se usan para escribir en la consola: Write() y WriteLine().






1)  WriteLine()
Totalmente equivalente a Console.WriteLine(), se utiliza la misma idea, y el mismo formato, sabiendo que se estará escribiendo el texto no a la consola, sino que al stream abierto con el constructor.

string linea = “Texto de prueba”;
ob.WriteLine(linea);
ob.WriteLine(“Los valores posibles son: {0} y {1}”, 3, 5);

2)  Write ()
También presente, el método simple Write(), permite escribir texto en el stream, de la misma forma que su equivalente método de la clase Console. En este caso se reconocen las siguientes alternativas de uso:

Imprimir un string:
string linea = “Texto de prueba”;
ob.Write(linea);

Imprimir un carácter:
char caracter = ‘T’;
ob.Write(caracter);

Imprimir un arreglo de caracteres:
char[] caracteres = new char[100];
for(int i=0; i<100; i++) caracteres[i] = ‘+‘;
ob.Write(caracteres);

Imprimir una porción de un arreglo de caracteres:
char[] caracteres = new char[100];
for(int i=0; i<100; i++) caracteres[i] = ‘+‘;
ob.Write(caracteres, 25, 50);
// Desde posición 25 se escriben 50 caracteres










No hay comentarios.:

Publicar un comentario