Curso de programación en .NET - Tema 1.40 - Archivos secuenciales, VB 2005.
1. Archivos secuenciales, VB.
1.1 Objetivos del tema.
Visto el acceso a un archivo, vamos a ver el acceso a un archivo secuencial utilizando un formato en ASCII delimitado como formato de grabación, que es el más estándar de todos.
1.2 Introducción.
Son archivos que se generan con una estructura que puede o no ser fija y que su lectura no puede ser direccionada.
Otro aspecto, es que por la estructura de datos generada en el archivo, la misma permita que se direccionen los registros, y que dicho archivo pueda ser abierto bajo otro formato distinto, de acceso aleatorio, pero eso es una particularidad, o una excepción, y también podríamos enfocarlo al revés, es decir es un archivo random, que se usa como archivo secuencial, para gustos los colores.
Otro aspecto sobre los archivos secuenciales, es que la estructura de datos que albergan no tiene porque ser una estructura fija, pueden ser registros con una estructura distinta de unos a otros, y además la longitud puede ser variable, siempre y cuando se este utilizando el formato de ASCII delimitado, que incorpora la delimitación de campos y de final de registro.
1.3 Abrir un archivo.
El primer paso para acceder a un archivo es siempre enlazarlo con el programa, abrirlo.
Lo primero es definir una variable que haga referencia al canal, en VB, la forma de identificar un archivo, es saber que canal de enlace utiliza con el sistema.
| Código: | | Dim Canal As Integer |
Después lo más cómodo es utilizar la función freefile, que nos devolverá un canal disponible, en lugar de tenerlo que gestionar nosotros.
| Código: | | Canal = FreeFile() |
Esta instrucción debe ejecutarse justo antes de abrir el archivo, nunca antes, si no la información obtenida puede no ser correcta.
El siguiente paso es realizar la apertura, en el modo que nos interese.
| Código: | | FileOpen(Canal, "Nombre.dat", OpenMode.Output) |
Para grabar datos la sintaxis es la que sigue:
| Código: | Dim Canal As Integer
Canal = FreeFile()
FileOpen(Canal, "Nombre.dat", OpenMode.Output) |
Para realizar una lectura:
| Código: | Dim Canal As Integer
Canal = FreeFile()
FileOpen(Canal, "Nombre.dat", OpenMode.Input) |
Para añadir datos, a un archivo ya existente.
| Código: | Dim Canal As Integer
Canal = FreeFile()
FileOpen(Canal, "Nombre.dat", OpenMode.Append) |
Matices, si se abre para grabar con Output, si el archivo existe perderá su contenido, si no existe se creará.
Si se abre para grabar con el modo Append, se añaden los datos a los que pudiera tener.
Si se abre con input se accede a él para leer su contenido.
1.4 Grabar una estructura de datos.
Bueno visto como efectuar la lectura y escritura en un archivo secuencial, conviene ampliar el tema para un archivo con una estructura algo más amplia.
Para la estructura de datos podemos utilizar un array o una colección, con el fin de almacenar los datos a utilizar en la misma.
La grabación de los datos no es nada más que la generación de un registro de datos con un formato en concreto, uno de los más extendidos es el ASCII delimitado.
En este formato se graban los datos numéricos separados por comas y los alfanuméricos encerrados entre comillas dobles.
VB integra directamente el formato ASCII delimitado, y no es necesario ningún tipo de acción especial.
Además permite grabar registros de longitud variable, bajo una única variable, útil para datos de texto.
Para la grabación de los datos de un registro podemos hacerlo bajo dos formatos.
La estructura se graba como una variable definida con una estructura de usuario.
| Código: | Public Structure Tiostro
Public Exped As String
Public Nomb As String
Public Ape1 As String
Public Ape2 As String
Public Domic As String
End Structure
Dim Registro as TipoRegistro |
Y grabar
| Código: | | WriteLine(Canal, Registro) |
O bien podemos grabar los datos en una variable cada uno de ellos, prescindiendo de la estructura.
| Código: | | WriteLine(Canal, Expediente, Nombre, Domicilio) |
1.5 Leer un registro.
El siguiente paso sería intentar leer el registro que hemos grabado anteriormente. Para la grabación sin usar la estructura la lectura es como sigue:
| Código: | Input(Canal, Expediente) ' código
Input(Canal, Nombre)
Input(Canal, Domicilio) |
Para la grabación usando la estructura la lectura es como sigue:
| Código: | | Input(Canal, Registro) ' código |
1.6 Lectura de un archivo secuencial.
La lectura de un archivo secuencial se basa siempre en el uso de un bucle del tipo mientras. La estructura de dicho bucle es la que sigue:
| Código: | While Not EOF(Canal)
' lectura de un registro
Input(Canal, Codigo)
Input(Canal, Denom)
Input(Canal, Cant)
Input(Canal, Preci)
' Realizar el proceso correspondiente.
End While |
1.7 Proceso de actualización.
El proceso de actualización se basa en el emparejamiento de registros, para ello los archivos han de estar grabados en secuencia, en caso contrario no es posible realizar un proceso adecuadamente correcto.
El sistema seguido es el de high value, viejo sistema utilizado en otros lenguajes de programación, pero no por ello menos efectivo.
La filosofía es la de emparejar registros como ya se explicó en el tema anterior.
Importante que el valor utilizado como High value, no sea alcanzable por los datos del archivo.
El proceso se basa en que solo puede haber proceso de actualización si los códigos coinciden, en ese caso puede darse el caso de borrado o actualización, pero nunca un alta, eso sería un error.
Si el código del archivo principal se adelanta al de los cambios, significa que los registros hasta igualarse deben ser del tipo alta, en caso contrario sería un error en la grabación del archivo de cambios.
Si el código del archivo principal se queda por detrás significa que ese código no dispone de incidencias, por lo que debe ser copiado tal como está en el archivo que se crea nuevo en el proceso, para no perder los datos que no van a sufrir cambios.
Siempre debemos disponer de una pareja de registros, por lo que al tratar un registro del archivo principal, inmediatamente hay que leer otro.
Igual con el de los cambios.
Por este motivo antes de entrar en el bucle de proceso, se debe cargar una pareja de registros fuera del bucle.
Al realizar la lectura en un archivo si se da la circunstancia de final de archivo, es cuando al código de ese archivo se le asigna el high value.
No sirve utilizar variables de tipo booleano, ni cualquier otra combinación, cuyo único resultado al final es maquiavélico, comparado con la sencillez de éste proceso.
A continuación exponemos el núcleo del proceso.
No está completo, se ha extraído lo esencial, y se ha realizado sin el uso de estructuras.
| Código: | If Not EOF(CanalMalum) Then
LeerMaes(CanalMalum, ExpedM, NombM, Ape1M, Ape2M, DomicM)
Else
ExpedM = Hv
End if
If Not EOF(CanalMoviv) Then
LeerMoviv(CanalMoviv, Exped, Nomb, Ape1, Ape2, Domic, Tipo)
Else
Exped = Hv
End IF
While Exped <> Hv Or ExpedM <> Hv
Select Case Exped
Case Is > ExpedM ' copiar maestro
Grabacion(CanalMaes, ExpedM, NombM, Ape1M, Ape2M, DomicM)
If Not EOF(CanalMalum) Then
LeerMaes(CanalMalum, ExpedM, NombM, Ape1M, Ape2M, DomicM)
Else
ExpedM = Hv
End if
Case Is < ExpedM
Select Case Tipo
Case "1" ' alta
Grabacion(CanalMaes, Exped, Nomb, Ape1, Ape2, Domic)
If Not EOF(CanalMoviv) Then
LeerMoviv(CanalMoviv, Exped, Nomb, Ape1, Ape2, Domic, Tipo)
Else
Exped = Hv
End IF
Case Else
' Error
LineaDet(Exped, Nomb, Ape1, Ape2, Domic, Tipo, "Actualiza")
If Not EOF(CanalMoviv) Then
LeerMoviv(CanalMoviv, Exped, Nomb, Ape1, Ape2, Domic, Tipo)
Else
Exped = Hv
End If
End Select
Case Is = ExpedM
Select Case Tipo
Case "1" ' alta, error
' Línea de detalle
LineaDet(Exped, Nomb, Ape1, Ape2, Domic, Tipo, "Alta")
If Not EOF(CanalMoviv) Then
LeerMoviv(CanalMoviv, Exped, Nomb, Ape1, Ape2, Domic, Tipo)
Else
Exped = Hv
End if
Case "2" ' baja, no se graba
If Not EOF(CanalMoviv) Then
LeerMoviv(CanalMoviv, Exped, Nomb, Ape1, Ape2, Domic, Tipo)
Else
Exped = Hv
End if
If Not EOF(CanalMalum) Then
LeerMaes(CanalMalum, ExpedM, NombM, Ape1M, Ape2M, DomicM)
Else
ExpedM = Hv
End if
Case "3" ' modificación, se graba el nuevo
Grabacion(CanalMaes, Exped, Nomb, Ape1, Ape2, Domic)
If Not EOF(CanalMoviv) Then
LeerMoviv(CanalMoviv, Exped, Nomb, Ape1, Ape2, Domic, Tipo)
Else
Exped = Hv
End if
If Not EOF(CanalMalum) Then
LeerMaes(CanalMalum, ExpedM, NombM, Ape1M, Ape2M, DomicM)
Else
ExpedM = Hv
End if
End Select
End Select
End While |
1.8 Cierre
Para ello se utiliza la instrucción FileClose(Canal)
Y se cierra cada uno de los archivos que nos interesa.
1.9 Ejercicios propuestos.
- Diseñe un registro de datos con los datos de los teléfonos de sus amigos. Grabe los datos con un archivo secuencial.
- Realizar el listado de esos datos en pantalla.
- Cree ahora un archivo igual al anterior y añádale el dato tipo y grabe datos en él. El campo tipo será 1 para nuevos datos, 2 para actualizar datos existentes, 3 para borrar datos.
- Realice el proceso de actualización del primer archivo con los datos del segundo.
1.10 Solución a los ejercicios propuestos.
Para la resolución de los siguientes ejercicios se han seguido métodos de lectura con estructura y sin estructura de datos, o tipos de usuario, con el fin de ilustrar que el archivo es independiente del programa, y además poder mostrar ambos formatos.
Se han utilizado los siguientes elementos en los ejercicios.
| Código: | Module Estructuras
Public Structure FilDatos
Public Codigo As String
Public Nomb As String
Public Ape1 As String
Public Ape2 As String
Public Domic As String
End Structure
Public Structure FilCambios
Public Codigo As String
Public Nomb As String
Public Ape1 As String
Public Ape2 As String
Public Domic As String
Public Tipo As String
End Structure
End Module
Module Funciones
Public Function Respuesta() As Boolean
Dim Resp As String
Do
Console.WriteLine("Los datos son correctos S/N.")
Resp = Console.ReadLine()
Loop Until UCase(Resp) = "S" Or UCase(Resp) = "N"
Respuesta = UCase(Resp) = "S"
End Function
End Module
Module Menu
Sub Main()
Dim Cual As String
Do
Console.Clear()
Console.WriteLine("1 Crea amigos ")
Console.WriteLine("2 Listar amigos ")
Console.WriteLine("3 Grabar cambios de amigos ")
Console.WriteLine("4 Actualización ")
Console.WriteLine("5 Cambiar archivos ")
Console.WriteLine("6 Final ")
Console.WriteLine("Seleccione opción ")
Do
Cual = Console.ReadLine
Loop Until Cual > "0" And Cual < "7"
Select Case CInt(Cual)
Case 1
GrabarDatos()
Case 2
Listar()
Case 3
GrabarCambios()
Case 4
Actualizacion()
Case 5
Try
FileSystem.Kill("Antiguo.Sec")
Catch
Finally
FileSystem.Rename("Amigos.Sec", "Antiguo.Sec")
FileSystem.Rename("Nuevo.Sec", "Amigos.Sec")
End Try
End Select
Loop Until Cual = "6"
End Sub
End Module |
1.-Diseñe un registro de datos con los datos de los teléfonos de sus amigos. Grabe los datos con un archivo secuencial.
| Código: | Module Grabar
Private Sub Validar(ByRef Codigo As String, ByVal UltCod As String)
If Codigo <> "" Then Codigo = Format(CInt(Codigo), "00000")
Select Case Codigo > UltCod
Case False
Codigo = ""
Console.WriteLine("El número de código está fuera de secuencia, el último
utilizado es el {0} ", UltCod)
Console.ReadKey()
End Select
End Sub
Private Sub Grabacion(ByVal Canal As Integer, ByVal Datos As FilDatos, ByRef
UltCod As String)
With Datos
WriteLine(Canal, .Codigo, .Nomb, .Ape1, .Ape2, .Domic)
UltCod = .Codigo
UltCod = Format(Val(UltCod), "00000")
Console.WriteLine("Datos grabados, pulse una tecla para seguir")
Console.ReadKey()
End With
End Sub
Public Sub GrabarDatos()
Dim Codigo As String
Dim UltCod As String
Dim Canal As Integer
Dim Datos As FilDatos
UltCod = ""
Canal = FreeFile()
FileOpen(Canal, "Amigos.sec", OpenMode.Output)
Do
Console.Clear()
Console.WriteLine("Grabar datos de los amigos.")
Console.WriteLine("Introduce el código del amigo")
Codigo = Console.ReadLine
Validar(Codigo, UltCod)
If Codigo <> "" Then
Datos.Codigo = Codigo
Console.WriteLine("Introduce el nombre.")
Datos.Nomb = Console.ReadLine()
Console.WriteLine("Introduce el primer apellido.")
Datos.Ape1 = Console.ReadLine()
Console.WriteLine("Introduce el segundo apellido.")
Datos.Ape2 = Console.ReadLine()
Console.WriteLine("Introduce el domcilio.")
Datos.Domic = Console.ReadLine()
Select Case Respuesta()
Case True
Grabacion(Canal, Datos, UltCod)
End Select
End If
Loop Until Codigo = ""
FileClose(Canal)
End Sub
End Module |
2.-Realizar el listado de esos datos en pantalla.
| Código: | Module Listado
Private Sub Cabecera()
Console.Clear()
Console.WriteLine("Listado de los amigos")
Console.WriteLine()
End Sub
Private Sub Visualizar(ByVal Datos As FilDatos)
With Datos
Console.WriteLine(" {0} {1} {2} {3} {4} ", .Codigo, .Nomb, .Ape1, .Ape2,
.Domic)
End With
End Sub
Public Sub Listar()
Dim Datos As FilDatos
Dim Canal As Integer = 1
Dim Lin As Integer
Canal = FreeFile()
FileOpen(Canal, "Amigos.sec", OpenMode.Input)
Cabecera()
While Not EOF(Canal)
' lectura de un registro
With Datos
Input(Canal, .Codigo) ' código
Input(Canal, .Nomb)
Input(Canal, .Ape1)
Input(Canal, .Ape2)
Input(Canal, .Domic)
End With
' Línea de detalle
Visualizar(Datos)
Lin = Lin + 1
' Control de fin de página
Select Case Lin Mod 20 = 0
Case True
Console.ReadKey()
Cabecera()
End Select
End While
FileClose(Canal)
Console.WriteLine()
Console.WriteLine("Listado finalizado, pulse una tecla para seguir")
Console.ReadKey()
End Sub
End Module |
3.-Cree ahora un archivo igual al anterior y añádale el dato tipo y grabe datos en él. El campo tipo será 1 para nuevos datos, 2 para actualizar datos existentes, 3 para borrar datos.
| Código: | Module Cambios
Private Sub Validar(ByRef Codigo As String, ByVal UltCod As String)
If Codigo <> "" Then Codigo = Format(CInt(Codigo), "00000")
Select Case Codigo > UltCod
Case False
Codigo = ""
Console.WriteLine("El número de código está fuera de secuencia, el último
utilizado es el {0} ", UltCod)
Console.ReadKey()
End Select
End Sub
Private Sub Grabacion(ByVal Canal As Integer, ByVal Datos As FilCambios, ByRef
UltCod As String)
With Datos
WriteLine(Canal, .Codigo, .Nomb, .Ape1, .Ape2, .Domic, .Tipo)
UltCod = .Codigo
UltCod = Format(Val(UltCod), "00000")
Console.WriteLine("Datos grabados, pulse una tecla para seguir")
Console.ReadKey()
End With
End Sub
Public Sub GrabarCambios()
Dim Codigo As String
Dim UltCod As String
Dim Canal As Integer
Dim Datos As FilCambios
UltCod = ""
Canal = FreeFile()
FileOpen(Canal, "Cambios.sec", OpenMode.Output)
Do
Console.Clear()
Console.WriteLine("Grabar cambios de los amigos.")
Console.WriteLine("Si es nuevo, el código no ha de existir, en caso
contrario sí.")
Console.WriteLine("Introduce el código del amigo.")
Codigo = Console.ReadLine
Validar(Codigo, UltCod)
If Codigo <> "" Then
Datos.Codigo = Codigo
Console.WriteLine("Introduce el nombre.")
Datos.Nomb = Console.ReadLine()
Console.WriteLine("Introduce el primer apellido.")
Datos.Ape1 = Console.ReadLine()
Console.WriteLine("Introduce el segundo apellido.")
Datos.Ape2 = Console.ReadLine()
Console.WriteLine("Introduce el domcilio.")
Datos.Domic = Console.ReadLine()
Console.WriteLine("Introduce el 1 para Nuevo, 2 para Cambios, 3 para Borrar.")
Datos.Tipo = Console.ReadLine()
Select Case Respuesta()
Case True
Grabacion(Canal, Datos, UltCod)
End Select
End If
Loop Until Codigo = ""
FileClose(Canal)
End Sub
End Module |
4.-Realice el proceso de actualización del primer archivo con los datos del segundo.
| Código: | Module Actualizar
Private Sub LeerAmigos(ByVal Canal As Integer, ByRef Codigo As String, ByRef Nomb As String, ByRef Ape1 As String, ByRef Ape2 As String, ByRef Domic As String)
' lectura de un registro
Input(Canal, Codigo) ' código
Input(Canal, Nomb)
Input(Canal, Ape1)
Input(Canal, Ape2)
Input(Canal, Domic)
End Sub
Private Sub Grabacion(ByVal Canal As Integer, ByRef Codigo As String, ByRef Nomb As String, ByRef Ape1 As String, ByRef Ape2 As String, ByRef Domic As String)
WriteLine(Canal, Codigo, Nomb, Ape1, Ape2, Domic)
End Sub
Private Sub LeerCambios(ByVal Canal As Integer, ByRef Codigo As String, ByRef Nomb As String, ByRef Ape1 As String, ByRef Ape2 As String, ByRef Domic As String, ByRef Tipo As String)
' lectura de un registro
Input(Canal, Codigo) ' código
Input(Canal, Nomb)
Input(Canal, Ape1)
Input(Canal, Ape2)
Input(Canal, Domic)
Input(Canal, Tipo)
End Sub
Private Sub Proceso(ByVal Canal As Integer, ByVal CanalC As Integer, ByVal CanalN As Integer)
Const Hv As String = "99999"
Dim CodCamb As String
Dim NombC As String
Dim Ape1C As String
Dim Ape2C As String
Dim DomicC As String
Dim Codigo As String
Dim Nomb As String
Dim Ape1 As String
Dim Ape2 As String
Dim Domic As String
Dim Tipo As String
If Not EOF(Canal) Then LeerAmigos(Canal, Codigo, Nomb, Ape1, Ape2, Domic) Else Codigo = Hv
If Not EOF(CanalC) Then LeerCambios(CanalC, CodCamb, NombC, Ape1C, Ape2C, DomicC, Tipo) Else CodCamb = Hv
While Codigo <> Hv Or CodCamb <> Hv
Select Case Codigo
Case Is < CodCamb ' copiar maestro
Grabacion(CanalN, Codigo, Nomb, Ape1, Ape2, Domic)
If Not EOF(Canal) Then LeerAmigos(Canal, Codigo, Nomb, Ape1, Ape2, Domic) Else Codigo = Hv
Case Is > CodCamb
Select Case Tipo
Case "1" ' alta
Grabacion(CanalN, CodCamb, NombC, Ape1C, Ape2C, DomicC)
End Select
If Not EOF(CanalC) Then LeerCambios(CanalC, CodCamb, NombC, Ape1C, Ape2C, DomicC, Tipo) Else CodCamb = Hv
Case Is = CodCamb
Select Case Tipo
Case "1" ' alta, error, habría que tratar el error
If Not EOF(CanalC) Then LeerCambios(CanalC, CodCamb, NombC, Ape1C, Ape2C, DomicC, Tipo) Else CodCamb = Hv
Case "2" ' modificación, se graba el nuevo
Grabacion(CanalN, CodCamb, NombC, Ape1C, Ape2C, DomicC)
If Not EOF(Canal) Then LeerAmigos(Canal, Codigo, Nomb, Ape1, Ape2, Domic) Else Codigo = Hv
If Not EOF(CanalC) Then LeerCambios(CanalC, CodCamb, NombC, Ape1C, Ape2C, DomicC, Tipo) Else CodCamb = Hv
Case "3" ' baja, no se graba
If Not EOF(Canal) Then LeerAmigos(Canal, Codigo, Nomb, Ape1, Ape2, Domic) Else Codigo = Hv
If Not EOF(CanalC) Then LeerCambios(CanalC, CodCamb, NombC, Ape1C, Ape2C, DomicC, Tipo) Else CodCamb = Hv
End Select
End Select
End While
End Sub
Public Sub Actualizacion()
Dim Canal As Integer
Dim CanalCamb As Integer
Dim CanalNuevo As Integer
' Abrir archivos
Canal = FreeFile()
FileOpen(Canal, "Amigos.sec", OpenMode.Input)
CanalCamb = FreeFile()
FileOpen(CanalCamb, "Cambios.sec", OpenMode.Input)
CanalNuevo = FreeFile()
FileOpen(CanalNuevo, "Nuevo.sec", OpenMode.Output)
Proceso(Canal, CanalCamb, CanalNuevo)
' cerrar todos los archivos
FileClose()
End Sub
End Module |
Autor del curso: casiopea |