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 If
En 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 If
En 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 If
En 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 If
En 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 If
En 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 If
En 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!