Técnicas Avanzadas de Procesado de Archivos: Uso de Bloques para la Gestión de Archivos Grandes

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!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *