Colabora |
Trabajando con ficheros desde C Sharp 2005Manipulación de ficheros binarios y texto
Fecha: 16/Jun/2007 (14 junio 2007)
|
Introducción¿Quién no ha necesitado el uso de ficheros al redactar un programa? ¿Quién a su vez no se ha complicado porque este y mas cual otro lenguaje de programación le hace la vida difícil para manejar los ficheros? El trabajo con ficheros siempre ha sido una cuestión vital dentro de todos los Entornos de Desarrollo Integrados (IDEs). Para esto, cada lenguaje implementa de una forma u otra mediante el uso de librerías, el acceso desde nuestra aplicación a los recursos del sistema. Las operaciones básicas sobre el uso de ficheros se consideran de lectura y escritura, aunque también se encuentran el manejo de los atributos del fichero hasta la creación y/o eliminación de carpetas de nuestro disco duro. Un poco de historiaDesde que surgieron los ordenadores han sido necesarios mecanismos para guardar la información de forma persistente en el disco duro. Los programas informáticos pueden almacenar la información en la RAM de su computadora mas al cerrar el programa los datos que tiene en su poder se pierden si no son almacenados previamente. De aquí surge la importancia del trabajo con ficheros, una funcionalidad que cada lenguaje de programación implementa para brindarles a los programadores la posibilidad de manejar la información de forma más eficiente y garantizar su durabilidad. Para quieres han programado con C++ o C, el trabajo con ficheros les traerá a la cabeza malos recuerdos (como es el caso de quien les escribe). Demasiadas declaraciones para conformar un fichero de entrada o salida, el uso de structs o ingenios algorítmicos, hacen del mismo una característica común para el trabajo con archivos. Con el surgimiento de la plataforma .NET llega a nosotros la caballería pesada, una serie de novedosas funcionalidades incluidas en un espacio de nombre que luego se hará famoso entre quienes aún, por desconocimiento o falta de apetito en nuevos lenguajes, no conoce, me refiero a System.IO. Como ya veremos más adelante el Framework 2.0 de .NET no se ha quedado atrás y ha propuesto para Visual Studio 2005 una mejor concepción del trabajo con ficheros tanto binarios como de texto. Pero antes, algunas definiciones referente a estos últimos para los novatos en el asunto. Fichero texto: Son aquellos que guardan la información en formato claro, es decir, si ud guarda la cadena string "Hola mundo" hacia un fichero de tipo texto llamado datos.txt, cuando lo abra, verá este mismo mensaje en su interior. Fichero binario: Son aquellos que guardan la información en formato no legible para los humanos, es decir, si ud guarda la cadena string "Hola mundo" hacia un fichero de tipo binario llamado datos.txt, cuando lo abra, su contenido no podrá ser leído por la persona en cuestión. Trabajando con la informaciónMuchos programadores se encuentran con la necesidad de guardar largas colecciones de objetos hacia fichero y también se enfrentan con la variante de poder trabajar con ficheros de texto o binario. Visto el epígrafe anterior se desprende el uso que se le dé a uno u otro tipo, está claro que si no queremos que nadie pueda ver por fuera de nuestra aplicación qué datos contiene una colección determinada, pues debemos utilizar los ficheros binarios y en caso contrario emplearíamos los de texto. A continuación veremos cómo trabajar tanto con ficheros binarios como de texto en conjunto con las listas de datos que podamos querer guardar en ellos, todo esto utilizando el lenguaje de programación C# desde el IDE Visual Studio 2005 y de paso, veremos las facilidades a las que hacía mención previamente. Ficheros binarios & Listas de ObjetosPara serializar/deserializar listas de objetos (guardarlos o abrirlos hacia/desde fichero) (Visual Studio 2005) Debes poner arriba de tu clase la etiqueta [Serializable], o sea, si quieres guardar/cargar una lista de trabajadores, pues debes ponerle esta etiqueta encima, quedaría así: [Serializable]
public class Trabajador
{
private int codigo;
private string nombre;
public int Codigo
{
get
{
return codigo;
}
set
{
this.codigo = value;
}
}
public string Nombre
{
get
{
return nombre;
}
set
{
this.nombre= value;
}
}
}
Esto le indica al compilador que tu clase está lista para ser usada como tal y con eso pues puedes realizar la serializacion de la propia clase o de Listas con tipo de esta clase. Si no le pones la etiqueta verás que no funcionará bien a la hora de aplicarle el código que te pongo a continuación. Para guardar una lista de objetos de este tipo de clase hacia fichero. using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; //Guardar una lista de Objetos a Fichero List<Trabajador> listTrab = (Método que devuelve datos de este tipo) IFormatter formatter = new BinaryFormatter(); FileStream fs = new FileStream(saveFileDialog1.FileName,FileMode.Create); formatter.Serialize(fs, listTrab); fs.Close(); Para cargarlos: using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; //Cargar una lista de Objetos desde Fichero IFormatter formatter = new BinaryFormatter(); FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open); //Puedes hacerlo así List<Trabajador> listTrab = (List<Trabajador>)formatter.Deserialize(fs); //O puedes hacerlo así List<Trabajador> listTrab = formatter.Deserialize(fs) as List<Trabajador>; fs.Close(); Ficheros Texto & Listas de Objetos
Para el caso del trabajo con ficheros texto y listas de objetos,
nos pudieran dar un fichero ya creado para nosotros construir una lista de algun tipo de dato con este. StreamWriter fw = new StreamWriter(path + "Listado de Clientes.txt");
foreach (ClientePersistente CP in list)
{
fw.WriteLine(CP.NumeroCoche + "-" + CP.Nombre + "-" +
CP.Direccion + "-" + CP.Modelo);
}
fw.Close();
Cuya salida sería esta: 1-Enrique Peraza-Avenida 1ra Rpto Esperanza-Mercedes Benz 10-Mercedez Concepción-Calle 5ta, Matanzas-Audi 11-Pedro Espinosa Pérez-Santiago de las Vegas, Habana-Ferrari 2-Rosa María del Rosario-San Jose Lajas Habana-Audi 3-Mirtha Menéses-Santa Clara, Cuba-Alpha Romeo 4-Angel de la Guarda-Sueño, Santiago de Cuba, Cuba-Peugeot 5-Miguel Angel Martínez-Camajuani, VC-Audi 6-Iliana Hdez-San Juan y Martínez, Habana-Peugeot 205 7-Yumilka Diaz-Ciego de Avila-Peugeot 206 8-Yoandy Echevarría-Habana-Mercedes Benz 9-Marcheco Pérez-Habana-Niva Como ven cada línea del fichero es un objeto, los atributos están separados en este caso por el carácter char '-'. Para construir una lista con estos clientes donde podemos identificar como atributos del objeto el identificador, el nombre, la dirección y el modelo de auto, podríamos hacer algo como esto: StreamReader fr = new StreamReader(path + "Listado de Clientes.txt"); List<ClientePersistente> listCliente = new List<ClientePersistente>(); while(!fr.EndOfStream) { string linea= fr.ReadLine(); string[] datos = linea.Split('-'); listCliente.Add(new ClientePersistente(datos[0], datos[1], datos[2], datos[3])); } fr.Close(); El split "picaría" en pedacitos una línea string. Estos pedacitos estarían delimitados por el carácter char '-' Estos pedacitos se guardan en un arreglo de tipo string. Esto es por supuesto para el caso donde la entrada fuera de la manera de que en cada línea sus atributos estuvieran separados por '-'. Si en lugar de estar separados por '-' estuvieran separados por dos espacios en blanco, o cualquier cadena mas compleja que un char, o sea un string, se debe sustituir la línea anterior del Split por esta: //Ejemplo para atributos separados por dos espacios en blanco. string[] datos = var.Split(new string[] {" "}, StringSplitOptions.RemoveEmptyEntries); Para el caso de un fichero texto generado con este método: StreamWriter fw = new StreamWriter(path + "Listado de Clientes.txt"); foreach (ClientePersistente CP in list) { fw.WriteLine(CP.NumeroCoche); fw.WriteLine(CP.Nombre); fw.WriteLine(CP.Direccion); fw.WriteLine(CP.Modelo); fw.WriteLine(); } fw.Close(); cuya salida sería esta: 1 Enrique Peraza Avenida 1ra Rpto Esperanza Mercedes Benz 10 Mercedez Concepción Calle 5ta, Matanzas Audi 11 Pedro Espinosa Pérez Santiago de las Vegas, Habana Ferrari 2 Rosa María del Rosario San Jose Lajas Habana Audi 3 Mirtha Menéses Santa Clara, Cuba Alpha Romeo 4 Angel de la Guarda Sueño, Santiago de Cuba, Cuba Peugeot 5 Miguel Angel Martínez Camajuani, VC Audi 6 Iliana Hdez San Juan y Martínez, Habana Peugeot 205 7 Yumilka Diaz Ciego de Avila Peugeot 206 8 Yoandy Echevarría Habana Mercedes Benz 9 Marcheco Pérez Habana Niva Haríamos nuestra lista de una manera un poco más sencilla pues no habría que usar el Split. Quedaría así: StreamReader fr = new StreamReader(path + "Listado de Clientes.txt"); List<ClientePersistente> listCliente = new List<ClientePersistente> (); while (!fr.EndOfStream) { string id = fr.ReadLine(); string nombre = fr.ReadLine(); string direccion = fr.ReadLine(); string modelo = fr.ReadLine(); fr.ReadLine(); listCliente.Add(new ClientePersistente(id,nombre,direccion,modelo)); } fr.Close(); Posibles dudasA continuación se exponen una serie de preguntas que pudieran convertirse en la duda de ud, amigo programador. Otra forma de pasarle a FileStream fs = new FileStream("paramValue", FileMode.Create) el parámetro que te puse en negrita, por ejemplo, sería: FileStream fs = new FileStream("C:\Documents and Settings\jalugo\ Desktop\archivo.txt", FileMode.Create) pero puedes darte cuenta que para múltiples propósitos tendrías que cambiarle manualmente al código, el camino para llegar al archivo, por tanto he utilizado la property FileName del componente SaveDialog que te devuelve en un string todo lo necesario para guardar el archivo. Pregunta 2: FileStream fs = new FileStream("C:\Documents and Settings\docencia\Desktop\archivo.txt", FileMode.Create); este es el error que me pone: Unrecognized escape sequence Respuesta: FileStream fs = new FileStream("C:\\Documents and Settings\\docencia\\Desktop\\archivo.txt", FileMode.Create); o de esta manera: FileStream fs = new FileStream(@"C:\Documents and Settings\docencia\ Desktop\archivo.txt", FileMode.Create); Fíjate en el arroba (@) para evitar tener que poner las barras dobles... Lo que pasa con el \ es que todos los \<algo>
son "caracteres de escape", que es la manera de expresar saltos de linea, tabulador etc. con @ se le dice al compilador que entienda
esa cadena de manera literal tal y como esta, la manera de hacer que se muestre \ es el caracter de escape \\. [Serializable] public class Datos { string text1, text2; DateTime dt; Image img; public Datos(string t1, string t2, DateTime dt, Image img) { this.text1 = t1; this.text2 = t2; this.dt = dt; this.img = img; } public string Text2 { get { return text2; } set { text2 = value; } } public string Text1 { get { return text1; } set { text1 = value; } } public DateTime Dt { get { return dt; } set { dt = value; } } public Image Img { get { return img; } set { img = value; } } } Si me preguntas como sé que Image es serializable, con el proyecto abierto desde el Visual Studio, da clic derecho encima de Image y selecciona "Go To Definition", verás que la clase implementa la interfaz "ISerializable". Resumiendo, utilizando la función Serialize y Deserialize se pueden guardar tipos de datos (con la etiqueta Serializable) que engloben otros tipos de datos serializables como es el caso de Image. Pregunta 4: Tengo un problema con mi fichero. Yo al inicio de mi programa le pido al usuario que entre su nick y contraseña los cuales estan guardados en un fichero y lo que hago es comprobar si estos datos son correctos. Hasta aqui no tengo problemas. El problema surge cuando al yo adicionar usuarios a mi fichero se me borran los anteriores que tenia. ¿Qué puedo hacer? Respuesta: Debes comprobar si estás abriendo el fichero en modo Create (FileMode.Create), caso con el cual te sobreescribe el fichero y por supuesto te borra lo que tenías anteriormente. Para solucionar esto lo debes poner en FileMode.Append, para que te ponga los nuevos datos al final del fichero que ya tienes creado... ConclusionesEl trabajo con ficheros texto al igual que con binarios es una tarea que resulta relativamente fácil para Visual C# 2005. Hemos visto cómo construir tanto ficheros textos como binarios que representen listas de objetos al igual que hemos aprendido a revertir el proceso, leyendo de los mismos y volviendo a construir dichas listas.
Espacios de nombres usados en el código de este artículo:
System.Runtime.Serialization - para el IFormatter
|
Código de ejemplo (comprimido): |
Fichero con el código de ejemplo: jalugo_trabajo_ficheros_CSharp.zip
- 14.20 KB
|