Developer's Diary

31 enero, 2011

Curso C# – Control de Ficheros I

Buenas, en está ocasión vamos a trabajar con el tratamiento de ficheros en C#. He decidido separar esta parte del curso en cuatro partes.

Primero trabajaremos con ficheros de texto y binarios, en la segunda parte veremos un poco de serialización, cuando lleguemos a la tercera parte veremos un poco más profundamente lo que contiene el espacio de nombres System.IO comprobando las clases Directory y File que resultan bastante útiles para el tratamiento de ficheros, además de volver a retomar algunos de los controles de dialog y ya finalmente en la cuarta parte realizaré una parte de tips, como ya hice con el capitulo de creación de clases.

Comencemos.

Como ya he indicado en esta primera parte, voy a comenzar explicando a trabajar tanto con ficheros binarios, como con ficheros de texto. Ahora os estareis preguntando que cual es la diferencia entre uno y otro. Es muy simple, mientras que los ficheros binarios contienen datos, en binario, es decir escribiremos byte a byte lo que contienen. Esto implica que aunque los abramos con un editor de texto, por ejemplo, no podremos identificar ningún dato, será la aplicación quien se encargue de identificarlo. Los ficheros de texto, serán completamente inteligibles por nosotros, ya que escribiremos texto plano.

Cuando debemos usar uno u otro, eso depende de la aplicación que estemos realizando, lo que si debemos tener en cuenta es que, en el primer caso. Nuestro fichero será inteligible por nuestra aplicación. Es decir, si nosotros dentro de nuestro fichero por ejemplo queremos introducir los datos de una persona: Nombre, edad y fecha de nacimiento, separando a cada persona por una coma y posteriormente, esa misma aplicación lee esos datos. Si hicieramos un cambio en la aplicación e introdujeramos posteriormente que también guardara el tipo sanguineo, nuesta aplicación, si no la cambiamos correctamente o si intentamos abrir un fichero de la antigua versión, con nuestra nueva versión, generaría errores.

No obstante en un fichero de texto, eso puede llegar a resultar más fácil de identificar, ya que los datos son tomados de otra manera.

Resumiendo, en fichero binario, tomamos los datos en bytes y debemos identificar correctamente esos bytes, en el caso de que la cantidad de bytes que tomemos no es de la longitud adecuada o intentemos identificar valores incorrectamente, ese fichero terminaría por dejar de funcionar. No estamos indicando que en un fichero de texto no pueda ocurrir tal cosa, si no que puede llegar a resultar más comodo de identificar los datos en el mismo.

Tratamiento de ficheros

Para trabajar con ficheros en .Net tenemos que tener en cuenta varias clases para cada una de las formas de generar ficheros. El uso de estas clases resulta más sencillo de lo que inicialmente puede parecer. Para trabajar con ficheros binarios usaremos las clases: BinaryReader y BinaryWritter, en el caso de usar ficheros de texto usaremos StreamReader y StreamWritter. Todas estás clases se encuentran dentro del espacio de nombres System.IO, que inicialmente cuando creamos una nueva aplicación no se encuentran implementada, debemos poner al inicio de nuestra aplicación la directiva “Using” seguida del espacio de nombres que vamos a usar “System.IO”

Ya tenemos cargado el espacio de nombres en nuestro proyecto, ahora vamos a comenzar a usar ficheros, para practicar con ficheros, lo más recomendable es trabajar en un proyecto de Windows Forms, esto se debe a que vamos a usar las controles de diálogo. OpenFileDialog y SaveFileDialog, que ya pudimos ver dentro del apartado del curso de controles de usuario. Gracias a estos dos controles vamos a poder crear más fácilmente nuestros ficheros y abrir los mismos para posteriormente leerlos.

Nuestro formulario, va a contener tres botones: uno que nos permita abrir el cuadro de diálogo para abrirlos y que posteriormente los abra, otro que nos permita introducir donde vamos a guardarlos y finalmente un tercero que nos permita salvarlos. Aunque es una aplicación de prueba, es recomendable tener algo de control de errores para acostumbrarnos, no nos interesa, que pulsemos el botón de guardar, cuando ni siquiera hemos seleccionado donde vamos a guardar tal fichero, por lo tanto el botón de salvar tendrá la opción de Enabled a false al inicio de la aplicación y posteriormente cuando seleccionemos la opción de guardar el fichero, volveremos a poner esa propiedad a true.

También vamos a introducir un textbox, con la propiedad MultiLine a true y vamos a habilitar los scrollbars, buscando la propiedad y situándola a both. Desde ese textbox, cargaremos los datos de nuestro fichero y por lo tanto nos interesa que tenga un tamaño considerable, principalmente porque nuestros ficheros van a tener cierto tamaño.

Finalmente vamos a introducir un checkbox, este checkbox nos permitirá, cambiar la apertura y creación de los ficheros de texto a binario, para incluir todas las pruebas en el mismo proyecto, no obstante, también podeis optar a crear dos proyectos uno para ficheros binarios y otro para ficheros de texto.

Vamos a comenzar a explicar como trabajar con cada uno de los ficheros.

Ficheros binarios

Inicialmente vamos a trabajar con ficheros binarios, como ya indicamos más arriba, los ficheros binarios tienen la particularidad de que los datos se encuentran almacenados por bytes y que si lo abrimos con un editor de texto, como puede ser el bloc de notas no podremos identificar la información ahí contenida.

Trabajar con ficheros binarios requiere de un proceso un poco mayor, que con ficheros de texto. Ahora explicaremos el por qué.

Las clases encargadas del tratamiento de ficheros binarios en .Net son BinaryReader, para lectura de los mismos y BinaryWritter para la escritura. A diferencia de cuando usamos ficheros de texto, en los ficheros binarios requerimos de una tercera clase, en la que apoyarnos, está es FileStream. Las clases que contienen el nombre Stream, permiten la carga de datos en bytes, se podría decir que es dentro de .Net la encargada de generar buffers de bytes. Cuando abrimos un fichero de tipo binario, debemos cargar los datos en un Stream y el BinaryReader será el que se encarga de ir leyendo esos datos desde el Stream.

Para poder cargar los datos de forma binaria en nuestra aplicación en .Net, sería de la siguiente manera.

Debemos primero instanciar o crear nuestra clase FileStream, la instanciación es muy parecida a la siguiente:

FileStream stream = new FileStream(nombrefichero , FileMode , FileAccess);

Posteriormente instanciariamos nuestra clase BinaryReader, con una instanciación como la siguiente:

BinaryReader reader = new BinaryReader(stream);

Como podemos comprobar solo le hemos tenido que pasar nuestro stream, internamente, la clase BinaryReader trabaja con el stream de datos.

Para la creación de la clase FileStream, hemos necesitado tres parametros, el nombre de fichero que es un simple string y requerimos de FileMode y FileAccess. Estos dos parametros, son enumeraciones que debemos pasarle también a nuestro FileStream es muy importante indicar correctamente las opciones de la enumeración porque puede no trabajar como nosotros desearíamos o incluso generar excepciones en tiempo de ejecución.

La primera enumeración es FileMode e indica la manera en la cual queremos abrir ese fichero existen un total de seis que son:

  • Append

Nos permite introducir nueva información en el fichero, normalmente se introduce tal información al final del mismo.

  • Create

Nos permite crear un nuevo fichero, en caso de que este ya exista se perdera toda la información y se volverá a generar.

  • CreateNew

En este caso creamos un nuevo fichero también, pero si existe, se generara una excepción

  • Open

En este caso abriremos un nuevo fichero, en caso de que no exista, se producirá una excepción.

  • OpenOrCreate

Con esta opción abriremos un fichero, si este fichero no existe, lo crearemos nuevo.

  • Truncate

Mediante esta opción abriremos un fichero y si este contenía información se perderá.

Cada una de las opciones tienes sus pros y contras, cada una de ellas es más recomendable según cual sean las funciones que vayamos a realizar con los ficheros.

El tercer parametro que pasamos es FileAccess, esta enumeración indica el nivel de acceso que vamos a tener de ese fichero, a nivel de ese FileStream. En este caso son tres las opciones y son las siguientes:

  • Write

Tendremos permisos de escritura del fichero.

  • ReadWrite

Tendremos permisos de escritura y lectura del fichero.

  • Read

Tendremos permisos de lectura sobre el fichero.

Como en el primer caso vamos a leer el fichero solamente, podríamos por ejemplo instanciar la clase FileStream con los siguientes parametros:

FileStream stream = new FileStream(nombrefichero , FileMode.Open , FileAccess.Read);

De esta manera nuestro fichero solo se abrira para la lectura y no tendremos peligro de realizar ningún tipo de modificación.

Ahora que tenemos nuestro fichero listo para ser leido de forma binaria, vamos a hacer un pequeña parada, para contar un poco de teoría cuando trabajamos con ficheros.

Cuando abrimos un fichero, debemos pensar que tenemos una aplicación de edición de texto abierta y tenemos nuestro cursor al inicio de esa información. Nuestra clase BinaryReader es ese cursor, por lo tanto cuando comenzamos a leer, ese cursor va avanzando, podemos instanciar todas las veces que queramos la clase BinaryReader y obtener un nuevo cursor para leer, incluso podemos ordenar a nuestro cursor que vuelva hacía atrás si este no los permite. Este cursor va a avanzar hasta que encuentre la sentencia EOF(End of File), si nosotros intentamos avanzar más adelante de esa indicación, produciremos un error, ya que estamos saliendo de la memoria de ese fichero y estaríamos entrando en la información de otro dato completamente distinto al que estamos abriendo o información inconsistente.

Un detalle de vital importancia cuando trabajamos con ficheros, es que cuando terminemos de trabajar con ese fichero, lo cerremos instántaneamente y siempre que podamos optar por cargar en memoria la información que necesitemos del fichero y posteriormente lo cerremos, esto mismo volveremos a repetirlo cuando comencemos a ver bases de datos. Ya que estamos consumiendo recursos que pueden necesitar otras aplicaciones o que no son realmente necesarios que estemos usando.

Después de indicar esto, continuamos viendo que podemos hacer con nuestro fichero binario recién abierto.

Tenemos varios métodos, que comienzan con la directiva Read. Según que método llamemos, nuestra aplicación entendera que debe leer un tipo de dato u otro. Esto quiere decir, que si dentro de nuestro fichero introducimos, dos números enteros y un caracter. Deberemos realizar la lectura de la misma manera, en caso contrario, podremos llegar a producir una excepción dentro de nuestra aplicación debido a que estamos entendiendo un tipo de dato por algo completamente distinto a lo que realmente quisimos operar con ese dato.

Ahora pasemos a escribir de manera binaria.

Para realizar una escritura debemos crear un objeto de tipo BinaryWritter además de usar el FileStream, si queremos cargar los datos de un fichero, por lo tanto, quedaría un código similar a este.

FileStream stream = new FileStream(fichero , FileAccess.ReadWrite , FileMode.OpenOrCreate);

Como se puede comprobar, en esta ocasión vamos a crear el fichero de manera distinta, evidentemente tenemos que escribir y leer y deberemos indicar que si existe lo abriremos, pero en caso contrario lo crearemos.

Instanciaremos el BinaryWriter de la misma manera que lo hicimos con el BinaryReader.

BinaryWriter writer = new BinaryWriter(stream);

En este caso tendremos un método llamado Write sobrecargado con cada uno de los tipos de dato que existen. Cuando nosotros realizemos una escritura dentro del fichero binario, introduciremos el tipo de dato del que se trata y deberemos codificarlo.

También se puede comprobar que existen otros tres métodos de los que debemos hacer mención. Flush(), que realizará una escritura sobre el fichero. Close() que realizará toda las escrituras pendientes y cerrará la conexión que tiene con el fichero y finalmente Peek. Este método nos permitirá desplazarnos por el fichero una cantidad de bytes. Hay que tener mucho ojo, con este detalle, nos permite desplazarnos un número de bytes, por lo tanto tenemos que tener en cuenta los valores en bytes de los distintos tipos de datos, para desplazarnos correctamente.

Por ejemplo, si estuviesemos introduciendo solamente chars dentro de nuestro fichero y quisieramos volver al quinto char escrito, deberíamos desplazarnos cinco bytes hacia atrás. Para poder hacerlo deberíamos introducir lo siguiente:

writer.Peek(5 , SeekOrigin.Begin);

Trabajar con ficheros en modo binario, puede resultar demasiado complicado, no obstante, en el próximo post relacionado con el curso, comprobaremos la serialización y entre ellas, la serialización binaria que nos permitirá trabajar con ficheros binarios de una manera mucho más sencilla.

Ficheros de Texto

Pasemos ahora a trabajar con ficheros de texto. El uso de ficheros de texto resulta mucho más sencillo que con ficheros binarios. En esta ocasión, no será estrictamente necesario el uso de un intermediario de tipo Stream, como ocurría con los ficheros binarios. Para trabajar con ficheros de texto, usaremos las clases StreamReader y StreamWriter. Ambas clases, también se encuentran en el espacio de nombres de System.IO, siempre que trabajemos con ficheros de texto, estaremos trabajando con cadenas de caracteres. Por lo que posteriormente deberemos identificar cada uno de los datos que hayamos introducido en nuestro fichero.

Un buen consejo para distinguir estos datos, sería por ejemplo, mediante el uso de comas o punto y coma, entre dato y dato. Generando una cadena que posteriormente podamos recuperar mediante un array, usando el método Split de las cadenas de caracteres.

No obstante, vamos a pasar a usar estos ficheros también. Inicialmente, vamos a leer los ficheros por lo tanto, usaremos la clase StreamReader. Podremos instanciarla de la siguiente manera:

StreamReader reader = new StreamReader(fichero);

Evidentemente, fichero debe ser una cadena que nos indique donde se encuentra ubicado ese fichero. Si examinamos lo que puede realizar la clase por nosotros veremos, varios métodos que comienzan con Read.

Lo interesante es ir probando cada uno de los métodos, para ver su funcionamiento. Aunque yo recomiendo usar el método ReadLine, porque nos permite tener controlado hasta que punto lee, sin complicarnos excesivamente. Una buena manera de leer un fichero de texto puede ser, crear un bucle while en donde nos apoyemos, con la propiedad de la clase EndOfStream, que nos permitira saber cuando se ha terminado el fichero e ir introduciendo esos datos dentro de una lista generica de string, quedando el código de la siguiente manera:

String fichero = string.Empty; //Ubicacion del fichero

StreamReader reader = new StreamReader(fichero);

List<string> ficheroleido = new List<string>();

While(reader.EndOfStream == false)

{

ficheroleido.Add(reader.ReadLine());

}

reader.Close();

De esa manera, tendré cada una de las líneas de mi fichero, almacenada en una lista de cadenas, luego solo tengo que trabajar con mi lista y hacer las gestiones necesarias. Como podeis comprobar, tras haber leido la información lo primero que he hecho, es cerrar el fichero. Vuelvo a insistir en la importancia de cerrar y terminar con el objeto de fichero, cuando hayamos terminado de realizar todas las funciones necesarias. Estamos accediendo a un recurso que puede darse la circunstancia de que necesite otra aplicación.

Bien, ahora pasemos a escribir en nuestro fichero de texto. Para ello, vamos a instanciar nuestra clase StreamWriter de la siguiente manera.

StreamWriter writer = new StreamWriter(fichero);

Y vamos a comprobar que nos permite hacer este objeto en cuestión, de nuevo nos volvemos a encontrar con el método Write, que se encuentra sobrecargado y que nos permite introducir cualquier tipo de dato, aunque después de pasar al fichero de texto, no dejará de convertirse en una cadena de datos, también tenemos el método WriteLine, que nos permite introducir una línea completa de texto.

Otra vez volvemos a encontrarnos con los métodos Close y Flush, que son de suma importancia para que los datos queden correctamente introducidos. Muy bien, vamos a suponer que queremos introducir un texto que hemos escrito dentro de un TextBox en un fichero de texto, ¿Como deberíamos hacerlo?. Pensemos que hemos pulsado en un botón para salvar los datos y entonces ejecutamos el guardado, el código que debemos introducir sería similar a este.

StreamWriter writer = new StreamWriter(fichero);

writer.WriteLine(TextBox1.Text);

writer.Close();

Así de sencillo, no debemos preocuparnos en el caso de que nuestro cuadro de texto tenga saltos de carro, porque se identifica como un caracter y este queda introducido en el fichero de texto. Como podeis comprobar, he llamado al método Close y no al método Flush, esto se debe a que el mismo método Close se encarga de realizar el volcado de datos, si hubiesemos continuado introduciendo datos, si deberíamos haber usado el método Flush, ya que posteriormente continuariamos introduciendo más datos.

Hasta aquí la primera lección de tratamiento de ficheros dentro de .Net. Como vereis no resulta demasiado difícil el uso de los mismos, debemos pensar que trabajar con ficheros, es como escribir en otra ventana externa a nuestra aplicación. No obstante, en posteriores lecciones comprobaremos como sacar un mayor partido a los ficheros, mediante la serialización.

Recordar, que si teneis alguna duda solo teneis que comentar y os responderé en la mayor brevedad posible.

Saludos.

Anuncios

2 comentarios »

  1. muy bien las explicaciones,fueron de mucha ayuda!!a seguir con el mismo método!!

    Comentario por Stella — 25 febrero, 2011 @ 12:29 AM

    • Me alegro que te hayan gustado, sigue pasando por la página que dentro de nada también enseñaremos a usar bases de datos.

      Un saludo.

      Comentario por 3nk1 — 25 febrero, 2011 @ 7:28 AM


RSS feed for comments on this post. TrackBack URI

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: