Saltar al pie de página
Iron Academy Logo
Novedades en C# y .NET

Async C#: Una inmersión profunda en Async Zip con Tim Corey

Tim Corey
24m 49s

La compresión y extracción de archivos son tareas esenciales para muchos desarrolladores de C#, ya sea que estés trabajando en una aplicación de escritorio, un servidor web o simplemente necesites archivar datos. Durante años, los desarrolladores de .NET podían crear, actualizar y extraer archivos zip de manera sincrónica, bloqueando el hilo de la interfaz de usuario o retrasando otras operaciones. Como explica Tim Corey en su video "Async Zip in .NET 10 – One Line Create or Extract And More", .NET 10 introduce operaciones asincrónicas para archivos zip, permitiendo a los desarrolladores escribir código eficiente que realice operaciones dependientes de I/O sin congelar la aplicación principal.

La programación asincrónica en C# se basa principalmente en objetos Task y Task, siendo la clase Task el componente principal para modelar trabajos en curso y habilitar la ejecución concurrente. El modelo de programación asincrónica basado en tareas (TAP) proporciona una capa de abstracción sobre la codificación asincrónica típica, facilitando la gestión de operaciones asincrónicas y excepciones. La clase System.Threading.Tasks.Task y los tipos relacionados se utilizan para implementar el modelo de programación asincrónica basada en tareas en C#.

En este artículo, seguiremos la explicación de Tim y mostraremos cómo realizar operaciones asincrónicas en C# para crear, extraer y comprimir archivos selectivamente, todo mientras se utiliza el patrón async/await, objetos Task y manejo adecuado de excepciones.

Introducción a la Programación Asincrónica y Async Zip en .NET 10

Tim comienza destacando la capacidad de larga data de C# para crear y extraer archivos zip. Sin embargo, con .NET 10, los desarrolladores ahora pueden usar código asincrónico para manejar estas tareas sin bloquear el hilo de llamada. Usando métodos async y la palabra clave await, operaciones como crear o extraer grandes archivos zip pueden ejecutarse en hilos de fondo, permitiendo que el hilo principal de la interfaz de usuario permanezca receptivo.

La palabra clave async es solo un decorador que indica al compilador de C# que el método contiene al menos una ocurrencia de la palabra clave await. La palabra clave await solo se puede utilizar dentro de un método async, y debe ir seguida de un objeto Task o Task.

Como explica Tim, esto es particularmente importante en aplicaciones que realizan múltiples tareas, como llamadas de red, consultas a bases de datos o I/O de archivos, donde esperar tareas permite que las tareas dependientes de la CPU continúen sin bloquear el hilo de llamada. Bloquear el código asincrónico con .Result o .Wait() convierte el código asincrónico en código sincrónico, lo cual puede llevar a interbloqueos.

Los métodos async devuelven objetos Task o Task, y devolver tareas permite una composición adecuada de tareas y concurrencia. Los métodos sin await se ejecutan de forma sincrónica. Al devolver objetos Task desde métodos asincrónicos, puedes coordinar múltiples operaciones en curso y manejar excepciones de manera más efectiva.

Configuración del proyecto

Tim comienza abriendo Visual Studio 2026 y crea una aplicación de consola llamada ZipFilesApp. Él nota que incluso los métodos static async Task Main se pueden usar para realizar tareas asincrónicas en el punto de entrada del programa, evitando bloquear el hilo principal. Al adaptar código existente, a menudo puedes envolver código sincrónico en Tareas o implementar variantes async para introducir comportamiento asincrónico sin reescribir toda la base de código.

Luego, él añade la directiva using esencial:

using System.IO.Compression;

Esto permite el acceso a métodos asincrónicos como CreateFromDirectoryAsync y ExtractToDirectoryAsync. Al crear métodos de llamada, es importante usar convenciones de nombres consistentes, como agregar el sufijo 'Async' a métodos asincrónicos, para distinguir claramente entre ellos y los sincrónicos. Nombres de métodos inconsistentes pueden llevar a confusión sobre si un método es sincrónico o asincrónico.

A continuación, Tim prepara tres variables de cadena para definir las rutas necesarias para las operaciones zip:

  1. Directorio de origen: la carpeta a comprimir.

  2. Archivo zip de destino: la ruta completa para guardar el archivo zip.

  3. Directorio de destino: la carpeta donde se almacenarán los archivos extraídos.

Tim menciona usar el símbolo @ en literales de cadena para evitar escapar barras invertidas, lo cual es un problema común en código sincrónico al escribir rutas de Windows. A lo largo de este artículo, se proporcionan ejemplos de código y fragmentos de código para ilustrar cómo implementar programación asincrónica en C#.

Creando un Archivo Zip Usando un Método Asincrónico

A las 3:47, Tim demuestra una operación asincrónica de una sola línea usando un método static async Task:

await ZipFile.CreateFromDirectoryAsync(
    sourceDirectory, 
    destinationZipFile, 
    CompressionLevel.SmallestSize, 
    includeBaseDirectory: false
);

Aquí, Tim explica varios aspectos importantes:

  • La palabra clave async marca este método asincrónico, permitiendo el uso de await.

  • await pausa la ejecución de este método asincrónico hasta que la tarea se complete, permitiendo que otras tareas o el hilo principal de la interfaz de usuario sigan ejecutándose. Esto demuestra cómo await trabaja y pausa la ejecución para asegurar un comportamiento no bloqueante en operaciones asincrónicas como I/O de archivos.

  • CompressionLevel.SmallestSize asegura una compresión eficiente.

  • El parámetro includeBaseDirectory controla si la carpeta raíz se incluye en el zip.

Este ejemplo muestra cómo el flujo de trabajo asincrónico en C# se gestiona con las palabras clave async y await, haciendo que el código sea más mantenible y simplificando el manejo de excepciones. La palabra clave await solo se puede usar dentro de un método async, como un método público async Task. Cuando se encuentra await, el compilador de C# genera una máquina de estados para gestionar el flujo de ejecución, pausando la ejecución, iniciando la tarea asincrónica y reanudándola una vez que se complete. Si el método async devuelve un valor, el resultado puede capturarse en una variable, como int resultado, para su uso posterior. Mediante async/await, los desarrolladores no tienen que crear manualmente hilos de fondo o tareas de grupo de hilos, ya que el compilador genera automáticamente la máquina de estados necesaria y el código de soporte.

Extrayendo un Archivo Zip Con Await Task Asíncronamente

Tim continúa con la extracción de un archivo zip con operaciones asincrónicas, usando otro método async:

await ZipFile.ExtractToDirectoryAsync(
    destinationZipFile, 
    destinationDirectory, 
    overwriteFiles: false
);

Destaca que el parámetro overwriteFiles maneja el manejo de excepciones en caso de que la carpeta ya exista. Por defecto, la extracción fallará si los archivos ya existen, pero establecerlo en true permite que la operación asincrónica reemplace los archivos existentes.

Al trabajar con código asincrónico, el manejo robusto de errores es crucial. Tim enfatiza la importancia de usar bloques try-catch para manejar excepciones en métodos async. No manejar excepciones adecuadamente en código async puede llevar a fallos silenciosos o bloqueos inesperados, ya que las excepciones lanzadas en tareas asincrónicas pueden no ser inmediatamente visibles. Siempre maneja excepciones para asegurar un comportamiento confiable de la aplicación.

Tim señala que este código asincrónico es seguro para múltiples tareas, lo que significa que no bloqueará otras solicitudes o llamadas de red que ocurran simultáneamente. Al usar la palabra clave await, el hilo de llamada es liberado hasta que la tarea termine, creando un flujo de programa receptivo.

Además, al definir métodos async, es importante usar async void solo para controladores de eventos, como clics de botones en aplicaciones GUI. En estos casos, la firma del método normalmente incluye (object sender, EventArgs e), donde object sender identifica la fuente del evento. Usar async void fuera de controladores de eventos puede llevar a un comportamiento impredecible y errores difíciles de diagnosticar, por lo que se prefiere async Task para la mayoría de los métodos asincrónicos.

Agregando Archivos Selectivamente a un Zip

A veces, los desarrolladores necesitan más control que simplemente comprimir una carpeta entera. Tim demuestra realizar operaciones asincrónicas selectivamente creando un FileStream:

await using FileStream zipStream = new FileStream(
    destinationZipFile, 
    FileMode.Create, 
    FileAccess.Write, 
    FileShare.None, 
    bufferSize: 4096, 
    useAsync: true
);

Al agregar archivos asincrónicamente, cada adición de archivo representa una tarea específica. Al iniciar todas las tareas para adiciones de archivo de forma concurrente y luego esperar su finalización usando métodos como Task.WhenAll, puedes mejorar significativamente el rendimiento. Gestionar tareas en ejecución de esta manera es esencial para escenarios de alta concurrencia, como cuando un servidor necesita procesar múltiples peticiones a la vez. Este enfoque también se usa comúnmente al interactuar con un servidor remoto, permitiendo que las aplicaciones permanezcan receptivas mientras esperan datos.

Tim explica cada detalle:

  • FileMode.Create – Asegura que se crea o sobrescribe un archivo zip nuevo.

  • FileAccess.Write – Permite escribir en el archivo.

  • FileShare.None – Impide que otras tareas accedan al archivo mientras se está escribiendo.

  • useAsync: true – Habilita la escritura asincrónica de archivos, una operación asincrónica básica.

Él nota que la programación async en este contexto evita bloquear el hilo principal mientras la tarea se completa, lo que es especialmente útil en servidores web que manejan múltiples tareas. Servidores de alta concurrencia aprovechan la programación asincrónica para manejar de manera eficiente múltiples solicitudes de clientes simultáneas sin generar un nuevo hilo por cada conexión. Sin embargo, escribir código async secuencialmente puede dificultar la lectura y depuración, ya que las tareas async pueden completarse fuera de orden.

Creando el Archivo Zip y Agregando Archivos

A continuación, Tim crea un ZipArchive asincrónicamente:

using ZipArchive archive = await ZipArchive.CreateAsync(
    zipStream, 
    ZipArchiveMode.Create, 
    leaveOpen: false, 
    entryNameEncoding: null
);
  • La expresión await asegura que la ejecución se pause hasta que la tarea finalice, haciéndola segura para proceder con la adición de archivos. Async y await simplifican la gestión de operaciones asincrónicas, haciendo que el código sea más fácil de leer y mantener en comparación con los enfoques tradicionales basados en callbacks.

  • Es importante notar que el mismo código puede comportarse de manera diferente dependiendo del contexto de sincronización. Por ejemplo, en aplicaciones WPF o WinForms, la presencia de un contexto de sincronización puede causar que la continuación después de una llamada await se ejecute en el hilo principal de la interfaz de usuario, mientras que en aplicaciones de consola, no hay tal contexto. Esto puede afectar cómo se ejecuta tu código async.

  • Al escribir código de biblioteca, considera usar ConfigureAwait(false) después de una llamada await para evitar cambios de contexto innecesarios y mejorar el rendimiento.

  • Usando Path.GetRelativePath, Tim explica cómo mantener la estructura de carpetas dentro del zip, lo cual es esencial cuando se realizan flujos de trabajo asincrónicos con múltiples archivos:
foreach (string filePath in Directory.GetFiles(sourceDirectory, "*", SearchOption.AllDirectories))
{
    string relativePath = Path.GetRelativePath(sourceDirectory, filePath);
    await archive.CreateEntryFromFileAsync(filePath, relativePath).ConfigureAwait(false);
}

Esto demuestra el código async en la práctica, donde cada adición de archivo es una llamada asincrónica, y la palabra clave await asegura la secuenciación adecuada mientras aún realiza I/O no bloqueante. El código asincrónico permite que el hilo actual permanezca desbloqueado, mejorando la capacidad de respuesta y permitiendo que el hilo realice otro trabajo mientras espera que las operaciones de I/O se completen.

Manejo de Acceso a Archivos y Manejo de Excepciones

Tim destaca un escenario común de manejo de excepciones: intentar extraer un zip antes de que la tarea original de FileStream se complete. Usar métodos asincrónicos limitados por alcance o métodos async Task sin declaraciones using adecuadas de alcance puede causar:

El proceso no puede acceder al archivo porque está siendo usado por otro proceso.

La solución es envolver la operación asíncrona en un bloque tradicional using de alcance para liberar recursos antes de la extracción:

await using (FileStream zipStream = new FileStream(...))
{
    using ZipArchive archive = await ZipArchive.CreateAsync(zipStream, ...);
    // Agregar archivos asíncronamente
}
// Ahora es seguro extraer

Esto asegura que el objeto tarea termine y libere el contexto de sincronización, evitando errores de bloqueo de archivos.

Conclusión: Zip Asíncrono Eficiente en .NET 10

Tim concluye que las operaciones asincrónicas de zip en .NET 10 permiten a los desarrolladores realizar operaciones asincrónicas de manera eficiente, evitar bloquear el hilo principal e integrarse sin problemas con otras tareas como llamadas de red o consultas a bases de datos.

Usando métodos Task asincrónicos estáticos, modificadores async y expresiones await, los desarrolladores pueden:

  • Comprimir o extraer archivos zip sin congelar el hilo de la interfaz de usuario.

  • Manejar múltiples hilos de manera segura sin gestión manual del grupo de hilos.

  • Realizar compresión selectiva mientras se preservan las estructuras de carpetas.

  • Asegurar un manejo adecuado de excepciones y limpieza de recursos.

Los ejemplos de Tim demuestran que async/await en operaciones de archivos no solo es conveniente, sino que es una parte esencial de la programación asincrónica moderna en C#.

Siguiendo su video, los desarrolladores pueden escribir código eficiente utilizando métodos asincrónicos, llamadas await y flujos de trabajo asincrónicos para manejar sin problemas tareas de compresión de archivos simples y complejas.

Hero Worlddot related to Async C#: Una inmersión profunda en Async Zip con Tim Corey
Hero Affiliate related to Async C#: Una inmersión profunda en Async Zip con Tim Corey

Gana más compartiendo lo que te gusta

¿Creas contenidos para desarrolladores que trabajan con .NET, C#, Java, Python o Node.js? ¡Convierte tu experiencia en un ingreso extra!

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame