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.