A continuación encontrarás traducido al castellano el artículo escrito por Martin T. y publicado originalmente en el Blog de Xojo.
Un artículo reciente, Usar Archivos de Texto en Xojo: Guía para principiantes, cubría los fundamentos de la gestión de archivos de texto con Xojo. Este artículo profundiza en técnicas avanzadas tanto para la lectura como para la escritura de archivos de gran tamaño en bloques. Este método es crucial para la gestión eficiente de grandes grupos de datos, minimizando el uso de memoria y manteniendo el rendimiento de la aplicación.
¿Por qué Leer y Escribir en Bloques?
La lectura o escritura de grandes archivos del tirón puede sobrecargar la memoria de tu aplicación y degradar su rendimiento. El procesado de archivos en porciones más pequeñas y manejables permite una mejor gestión de memoria y también contar con aplicaciones más ágiles.
Lectura de Archivos en Bloques
Para leer un archivo de gran tamaño en bloques puedes leer de forma repetida pequeñas porciones del archivo hasta que se llega hasta su final. He aquí un ejemplo:
Var file As FolderItem = FolderItem.ShowOpenFileDialog("text/plain")
If file <> Nil Then
Const kChunkSize As Integer = 1024 // bloques de 1 KB
Var inputStream As TextInputStream = TextInputStream.Open(file)
Var buffer As String
While Not inputStream.EndOfFile
buffer = inputStream.Read(kChunkSize)
// Procesa el buffer (para nuestra demostración, nos limitamos a imprimirlo)
System.DebugLog(buffer)
Wend
inputStream.Close
Else
MessageBox("No se ha seleccionado ningún archivo.")
End IfEn este ejemplo:
- Se crea un TextInputStream para leer el archivo.
- La constante kChungSize define cuántos datos se leerán cada vez.
- Se lee el archivo en un bucle hasta que se alcance el final de dicho archivo, procesando cada bloque de datos.
Escribir Archivos en Bloques
Escribir archivos de gran tamaño en bloques implica escribir de forma incremental pequeñas porciones de datos, utilizando para ello String.Bytes y String.MiddleBytes de modo que se obtenga un mejor rendimiento:
Var file As FolderItem = FolderItem.ShowSaveFileDialog("text/plain", "example.txt")
If file <> Nil Then
Const kChunkSize As Integer = 1024 // Bloques de 1 KB
Var outputStream As TextOutputStream = TextOutputStream.Create(file)
Var data As String = "Sustituir por una cadena de texto de gran tamaño…" // Tu fuente de datos
Var totalBytes As Integer = data.Bytes
For i As Integer = 0 To totalBytes Step kChunkSize
Var chunk As String = data.MiddleBytes(i, kChunkSize)
outputStream.Write(chunk)
Next
// Escribir los datos remanentes
If totalBytes Mod kChunkSize <> 0 Then
Var remainingBytes As Integer = totalBytes Mod kChunkSize
Var chunk As String = data.MiddleBytes(totalBytes - remainingBytes, remainingBytes)
outputStream.Write(chunk)
End If
outputStream.Close
MessageBox("Archivo escrito con éxito.")
Else
MessageBox("No se ha indicado ningún archivo.")
End IfEn este ejemplo:
- Se crea un TextOutputStream para escribir en un archivo.
- Se calcula la cantidad total de bytes para la iteración.
- Los datos se escriben en bloques definidos mediante kChunkSize utilizando String.MiddleBytes para mejorar el rendimiento.
- Tras el bucle, se escribe cualquier dato remanente que no haya cabido en cualquiera de los bloques anteriores.
Ejemplo Práctico: Procesar Archivos de Registro de Gran Tamaño
El procesado de archivos de registro de gran tamaño línea a línea puede realizarse de la siguiente forma:
Var file As FolderItem = FolderItem.ShowOpenFileDialog("text/plain")
If file <> Nil Then
Const kChunkSize As Integer = 4096 // bloques de 4 KB
Var inputStream As TextInputStream = TextInputStream.Open(file)
Var buffer, remaining As String
While Not inputStream.EndOfFile
buffer = inputStream.Read(kChunkSize)
buffer = remaining + buffer
Var lines() As String = buffer.ToArray(EndOfLine)
// Procesa todo salvo la última línea
For i As Integer = lines.FirstIndex To lines.LastIndex - 1
System.DebugLog(lines(i))
Next
// Guarda la última línea para el siguiente bloque
remaining = lines(lines.LastIndex)
Wend
// Procesa cualquier contenido restante
If Not remaining.IsEmpty Then
System.DebugLog(remaining)
End If
inputStream.Close
Else
MessageBox("No se ha seleccionado ningún archivo.")
End IfEn este ejemplo:
- Se leer el archivo en bloques de 4 Kb.
- Se divide el buffer en líneas, y se procesan todas menos la última.
- Se guarda la última línea y se suma al siguiente bloque para garantizar que no se pierde ningún dato.
Técnicas avanzadas: Gestión de Archivos Binarios
La lectura y escritura de archivos binarios también se beneficia del procesamiento en bloques. Este es un ejemplo básico sobre cómo leer archivos binarios en bloques:
Var file As FolderItem = FolderItem.ShowOpenFileDialog("")
If file <> Nil Then
Const kChunkSize As Integer = 1024 // bloques de 1 KB
Var binaryStream As BinaryStream = BinaryStream.Open(file, False)
Var buffer As MemoryBlock
While Not binaryStream.EndOfFile
buffer = binaryStream.Read(kChunkSize)
// Procesa el buffer (para nuestra demostración, nos limitamos a imprimirlo)
System.DebugLog(buffer.Size.ToString)
Wend
binaryStream.Close
Else
MessageBox("No se ha seleccionado ningún archivo.")
End IfEn este ejemplo:
- Se crea un BinaryStream para leer el archivo.
- Se leen los datos en bloques y se procesan.
Escribir Archivos Binarios en Bloques
También puedes escribir archivos binarios en bloques. Este es un ejemplo básico:
Var file As FolderItem = FolderItem.ShowSaveFileDialog("text/plain", "example.txt")
If file <> Nil Then
Var binaryStream As BinaryStream = BinaryStream.Create(file, True)
Const kChunkSize As Integer = 1024 // bloques de 1 KB
Var data As MemoryBlock = ... // Tu fuente de datos en formato binario
Var totalBytes As Integer = data.Size
For i As Integer = 0 To totalBytes Step kChunkSize
Var chunk As MemoryBlock = data.MidB(i, kChunkSize)
binaryStream.Write(chunk)
Next
// Escribe los datos remanentes
If totalBytes Mod kChunkSize <> 0 Then
Var remainingBytes As Integer = totalBytes Mod kChunkSize
Var chunk As MemoryBlock = data.MidB(totalBytes - remainingBytes, remainingBytes)
binaryStream.Write(chunk)
End If
binaryStream.Close
MessageBox("Archivo binario creado con éxito.")
Else
MessageBox("No se ha indicado ningún archivo.")
End IfEn este ejemplo:
- Se crear un BinaryStream para escribir a un archivo.
- Se escriben los datos en bloques utilizando MemoryBlock.MidB para gestionar los datos binarios.
- Tras el bucle, se escribe cualquier dato remanente que no haya sido comprendido en los bloques anteriores.
Usar Hilos para Operaciones con Archivos de Gran Tamaño
Cuando se trabaja con archivos de gran tamaño deberías de considerar el uso de Threads (hilos) para las operaciones de lectura y escritura. Esto permite que la interfaz de usuario continúe siendo operativa al tiempo que las operaciones relacionadas con los archivos se realizan en segundo plano.
Ejemplo de cómo leer un archivo de gran tamaño en un hilo:
Class FileReadThread Inherits Thread
Private mFile As FolderItem
Sub Constructor(file As FolderItem)
mFile = file
End Sub
Sub Run()
Const kChunkSize As Integer = 1024 // bloques de 1 KB
Var inputStream As TextInputStream = TextInputStream.Open(mFile)
Var buffer As String
While Not inputStream.EndOfFile
buffer = inputStream.Read(kChunkSize)
// Procesa el buffer (en nuestra demostración, sólo lo imprimimos)
System.DebugLog(buffer)
Wend
inputStream.Close
End Sub
End Class
// Uso
Var file As FolderItem = FolderItem.ShowOpenFileDialog("text/plain")
If file <> Nil Then
Var fileThread As New FileReadThread(file)
fileThread.Run
Else
MessageBox("No se ha seleccionado ningún archivo.")
End IfEn este ejemplo:
- Se crea una subclase de Thread para gestionar la lectura del archivo.
- La IU principal continúa siendo funcional al tiempo que el hilo procesa el archivo en segundo plano.
Conclusión
Gestionar archivos de gran tamaño de forma eficiente es crucial para desarrollar aplicaciones robustas con Xojo. Mediante la lectura y escritura de los archivos en bloques, puedes gestionar mejor el uso de la memoria y asegurar que tu aplicación continúe siendo funcional incluso cuando tiene que lidiar con grandes tamaños de datos. Experimenta con estas técnicas en tus proyectos para experimentar las ventajas obtenidas.
¡Feliz programación!