Des-serializar archivos de texto en Visual Basic .Net
El otro dia en el instituto al que voy a estudiar, el profesor estaba dictando una clase de como usar persistencia con archivos de texto, asi como ya habiamos dado como usarla con archivos binarios, y archivos XML.
Como muchos saben, Visual Basic ofrece muchas funciones, que la mayoria de las veces son buenas para salir del apuro, o del estress, no se si ustedes han programando en VB .Net, pero les digo.. que es algo que a veces es un lenguaje muy facil, y basico.. con muchas funciones predeterminadas, que no ayudan para nada a crecer como programador, ya que nos quita logica al programa y logica a nuestros cerebros que tendrian que ser los que tendrian que estar pensando la logica de cada funcion, como hacer esto, y como hacer lo otro.
Esto me vino a la cabeza, cuando yo, muy emocionado.. porque el profesor habia dicho que ibamos a usar archivos de texto, y teniamos que levantar datos de un archivo de texto que por ejemplo tuviera los datos asi:
datoDelusuario1-datoDelusuario1-datoDelusuario1
datoDelusuario2-datoDelusuario2-datoDelusuario2
datoDelusuario3-datoDelusuario3-datoDelusuario3
datoDelusuario4-datoDelusuario4-datoDelusuario4
Y asi sucesivamente, me brillaron los ojos, dije: “Si! vamos a hacer funciones de las grosas”, mientras pensaba todo, muy ilusionado, el profesor.. se pone a escribir en el pizarron como hacerlo… fueron unas 10 lineas (no mas, seguramente) y ya estaba todo hecho, no necesitabamos ni pensarlo…
Pero! con la emocion que tenia encima, y aunque el profesor siguiera dictando la clase, fui pensando como hacer el serializador, y luego, cuando pense postearlo en el blog, fue cuando me decidi a hacerlo, y tratar de compartir un poco mis conocimientos de programacion, use alguna que otra funcion predeterminada de Visual Basic, en fin.. no todos somos perfectos, lo que mas me importa es que intenten entender la logica del des-serializador, y tratar de que entiendan como formatearlos para que queden lo mas parecidos a tablas.
Ok, manos a la obra, lo primero, cada dato no tiene mas longitud que 20 caracteres (esto supuestamente lo definimos en el programa con el que creamos el archivo de texto base, el mio se parece a esto:
Maltray*2546889*matias.a18@gmail.com
mnosh*55668997788*mnox@gmail.com
bony*455568899*bony@gmail.com
usuario5*contraseña5*mail5@gmail.com
Donde * es el caracter separador y la secuencia de datos esta dada asi: usuario*contraseña*email.
Ok, nuestra meta es que el archivo destino, al que le podemos poner cualquier nombre que nosotros quieramos, quede de esta manera:
Maltray 456456456 matias.a18@gmail.com
Mnosh 45645646465 mnosh@gmail.com
…
Obviamente, mas formateado, vamos a tratar de hacer lo que puedamos con nuestros querios archivos .txt.
Asi que aqui vamos, primero voy a presentarles el modulo, en donde se piden 3 datos:
- Archivo serializado (ej: D:\Archivo.txt)
- Caracter separador (Solo un caracter)
- Archivo destino (ej: archivoDesserializado.txt)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | Sub Main() 'Declaramos las variables que usaremos.. '@rutaArchivo sera la ruta del archivo existente del cual tomaremos datos y los serializaremos '@caracter sera el caracter separador que tenga entre dato y dato '@rutaNuevoArchivo sera la ruta del archivo en el cual guardaremos nuestros datos serializados. '@arr es la coleccion de lineas que tendremos en nuestro archivo, lo recibimos de la funcion Deserializar, 'de la clase Serialidor. Dim rutaArchivo As String Dim caracter As String Dim NuevoArchivo As String Dim arr As ArrayList Console.WriteLine("### String Reader ###" & vbCrLf) 'Este Do no saldra del bucle hasta que se le de un archivo que exista, y que su extension sea .txt. Do Console.Write("Inserte la ruta del archivo .txt que vamos a leer (por ejemplo C:\archivo.txt): ") rutaArchivo = Console.ReadLine() Loop While Serializador.ValidarRutadeArchivo(rutaArchivo) = False 'Este Do no saldra del bucle hasta que se le inserte una cadena de texto de 1 caracter. Do Console.Write("Inserte el caracter separador: ") caracter = Console.ReadLine() Loop While caracter.Length = 0 Or caracter.Length >= 2 'Este Do no saldra del bucle hasta que se le inserte un nombre de archivo valido (.txt) y el archivo 'no este creado. Do Console.Write("Inserte el nombre del nuevo archivo serializado: ") NuevoArchivo = Console.ReadLine() Loop While Serializador.ValidarNombredeArchivo(NuevoArchivo) = False 'Con los datos antes obtenidos, podemos instanciar nuestro serializador, el cual se encargara de des-serializar 'nuestro archivo con cadenas de texto separadas por un caracter, y crear uno nuevo mas ordenado Dim Serializator As New Serializador(rutaArchivo, NuevoArchivo, caracter) 'Corremos la funcion Deserializar, y obtenemos una lista de elementos. arr = Serializator.Deserializar() 'Si arr no es nada (lo que quiere decir que habian datos en el archivo, y que no hubo ningun error corriendo 'la deserializacion. If arr IsNot Nothing Then 'Serializamos en nuestro nuevo archivo le mandamos a este evento la coleccion de strings que tengamos 'dentro de ella, y mostramos mensaje de que todo salio bien. Serializator.Guardar(arr) Console.WriteLine("Archivo des-serializado satisfactoriamente") Else 'Ocurrio un error al serializar, asi que mostramos un mensaje de que no se pudo realizar satisfactoriamente. Console.WriteLine("Error al serializar / deserializar el archivo.") End If Console.WriteLine("Presione una tecla para salir del programa...") Console.ReadKey() End Sub |
Bien, ahora que hemos visto como funciona el modulo, les presento la clase Serializador:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | 'Importamos librerias que nos serviran para el manejo de archivos. Imports System.IO Imports System Public Class Serializador Private mRutaArchivo As String Private mNuevoArchivo As String Private mCaracter As String Private datosPorLinea As Integer Public Property RutaArchivo() As String Get Return Me.mRutaArchivo End Get Set(ByVal value As String) Me.mRutaArchivo = value End Set End Property Public Property NuevoArchivo() As String Get Return Me.mNuevoArchivo End Get Set(ByVal value As String) Me.mNuevoArchivo = value End Set End Property Public Property Caracter() As String Get Return Me.mCaracter End Get Set(ByVal value As String) Me.mCaracter = value End Set End Property Sub New(ByVal rutaArchivo As String, ByVal nuevoArchivo As String, ByVal caracter As Char) Me.RutaArchivo = rutaArchivo Me.NuevoArchivo = nuevoArchivo Me.Caracter = caracter End Sub Public Shared Function ValidarRutadeArchivo(ByVal rutaArchivo As String) As Boolean If File.Exists(rutaArchivo) Then Return True Else Return False End If End Function Public Function Deserializar() As ArrayList '@arch, es el archivo que se nos envio hoy desde el modulo, en el cual trabajaremos en la primera parte de la funcion. '@arr, es la coleccion de datos que obtendremos separandolos por el caracter separador. '@linea, es la linea de arch en la que estamos. '@i, es un contador auxiliar, usado para recorrer caracter por caracter en cada linea de @arch '@datoAux, cargaremos en esta variable dato por dato que vayamos recibiendo. '@ret, vamos a guardar en esta coleccion las lineas que va a tener el futuro archivo que creemos. '@cantidadLineas, la cantidad de lineas que tiene el archivo que estamos leyendo. '@cantidadDatos, la cantidad de datos total que obtenemos del archivo (para poder sacar cuantos datos hay por linea) - la usaremos en conjunto con @cantidadLineas -. '@texto, esta variable la usaremos por cuantas lineas tengamos en el archivo que estamos leyendo, nos servira para guardar datos en el array, ya formateados. Dim arch As New StreamReader(RutaArchivo) Dim arr As New ArrayList Dim linea As String = arch.ReadLine() Dim i As Integer = 0 Dim datoAux As String = "" Dim ret As New ArrayList Dim cantidadLineas As Integer Dim cantidadDatos As Integer Dim texto As String = "" 'mientras la linea que estemos leyendo no este vacia... While Not linea Is Nothing 'con este for recorremos toda la linea For i = 0 To linea.Length - 1 'chequeamos si el caracter en el que estamos parados ahora mismo en la linea es el caracter separador If linea.Chars(i) = Caracter Then 'si lo es, entonces guardamos el dato en el array, sumamos uno a la cantidad de datos y vaciamos datosAux arr.Add(datoAux) datoAux = "" cantidadDatos += 1 Else 'Sino, agregamos el caracter a nuestro string datosAux datoAux += linea.Chars(i) End If Next 'Agregamos el ultimo dato de la linea, como necesita el caracter separador y el ultimo dato no lo tiene. arr.Add(datoAux) 'Borramos datosAux datoAux = "" 'Leemos otra linea del archivo. linea = arch.ReadLine() 'Agregamos uno a la cantidad de lineas, y uno mas a la cantidad de datos (por el ultimo dato que agregamos). cantidadLineas += 1 cantidadDatos += 1 End While 'Obtenemos la cantidad de datos por linea dividiendo la cantidad de datos por la cantidad de lineas, y cerramos 'el archivo. datosPorLinea = cantidadDatos / cantidadLineas arch.Close() 'Si array es nada, entonces devolvemos nothing (y desde el modulo, pretenderemos que hubo un error). If arr Is Nothing Then Return Nothing Else 'Sino, instanciamos 3 variables que nos ayudaran para guardar los datos bien formateados en la coleccion ret '@j, es el contador que nos ayudara a recorrer @arr. '@x, es como decir, el "formateador", nos ayudara a formatear nuestros datos y agregarle los espacios 'necesarios a la derecha para que queden 20 caracteres por dato (suponiendo que los datos no son mas largos 'de 19 caracteres). '@y, es la suma de j + 1 para luego poder hacer el MOD satisfactoriamente. Dim j As Integer Dim x As Integer Dim y As Integer For j = 0 To arr.Count - 1 'Recorremos la coleccion, y agregamos a nuestra variable @texto el contenido de cada item. texto += arr.Item(j) For x = arr.Item(j).ToString.Length To 20 texto += " " 'Hasta que el largo de la cadena @texto sea 20, agregaremos un espacio a la cadena. Next y = j + 1 If y Mod datosPorLinea = 0 Then 'Si y MOD (resto de la division) datos por linea es igual a 0. ret.Add(texto) texto = "" 'Agregamos a @ret la cadena de texto, y vaciamos la variable @texto. End If Next End If 'Retornamos nuestra coleccion. Return ret End Function Public Sub Guardar(ByVal arr As ArrayList) '@arch, el archivo que crearemos y en el cual guardaremos los datos formateados. Dim arch As New StreamWriter(NuevoArchivo) For Each linea As String In arr 'Recorremos la coleccion que se nos dio cuando recibimos los datos, y por cada item de la coleccion 'escribimos una nueva linea con esa cadena y pasamos al siguiente renglon (WriteLine hace eso, si fuera 'solo Write escribiria todo en una linea). arch.WriteLine(linea) Next 'Cerramos el archivo. arch.Close() End Sub Public Shared Function ValidarNombredeArchivo(ByVal nombre As String) As Boolean If nombre.Contains(".") Then 'Si nombre contiene un . deducimos que se trataria de un archivo.. salvo para las personas que les guste 'decir "JA! te cague el programa! si le pongo dos . . se cae!", y bueno.. todo perfecto no se puede hacer. '@datos, un array String que mediante la funcion String.Split obtendremos (si no pasa lo antes mencionado), 'dos datos, en la posicion 0 del array, obtendremos el nombre del archivo, y en la 1, la extension.. 'que es lo que nos importa a nosotros. Dim datos() As String datos = nombre.Split(".") If datos(1) = "txt" Then 'Si la extension es igual a txt, entonces retornamos true, porque sabemos que se trata de un archivo 'de texto.. Return True Else 'Sino, retornamos false. Return False End If Else 'Si no contiene . quiere decir que no contiene extension tampoco, por lo que retornamos false. Return False End If End Function End Class |
Esta todo explicado dentro de la clase, para probar que funcionara, cree un archivo que se llamaba archivo.txt y contenia lo siguiente:
Maltray*2546889*matias.a18@gmail.com
mnosh*55668997788*mnox@gmail.com
bony*455568899*bony@gmail.com
usuario5*contraseniaaaa5*mail5@gmail.com
Le puse en caracter separador, *, y en nuevo archivo: note.txt.
El resultado fue, en la carpeta bin/Debug (del proyecto) se creo un archivo note.txt con lo siguiente:
1 2 3 4 | Maltray 2546889 matias.a18@gmail.com mnosh 55668997788 mnox@gmail.com bony 455568899 bony@gmail.com usuario5 contraseniaaaa5 mail5@gmail.com |
La solucion esta toda en el siguiente zip que les voy a poner, el archivo para des-serializar y probarlo tambien esta ahi, y tambien les dejo el archivo note.txt para que vean bien como quedo.
Recordar que la solucion esta creada con Visual Basic 2008, por lo que, si tenemos uno mas viejo dudo que puedan verlo.
Link: http://hotfile.com/dl/20229098/5ffbf78/Leer_String.rar.html
Pass: http://www.informaticavirtual.us
En el se encuentran:
Leer String (Directorio): Contiene la solucion para Visual Studio 2008
note.txt: El archivo creado por nuestro programa a partir de archivo.txt
archivo.txt: El archivo a des-serializar
Espero que les haya gustado, costo un poco hacer este post y este programa, pero despues de todo, salio.
Saludos.