Saltar al contenido principal

Compresión

El CompressionMiddleware reduce el tamaño de los archivos antes de almacenarlos usando GZip. La descompresión se aplica automáticamente al descargar, de forma completamente transparente. El estado de compresión se registra en el metadato x-vali-compressed.

Activación

.WithPipeline(p => p
.UseCompression(c =>
{
c.CompressionLevel = CompressionLevel.Optimal;
c.MinSizeToCompress = 1024; // No comprimir archivos menores a 1 KB
c.SkipAlreadyCompressedTypes = true; // No recomprimir tipos ya comprimidos
})
)

CompressionOptions

public class CompressionOptions
{
/// <summary>Nivel de compresión GZip. Por defecto: Optimal.</summary>
public CompressionLevel CompressionLevel { get; set; } = CompressionLevel.Optimal;

/// <summary>Tamaño mínimo en bytes para comprimir. Archivos menores se omiten.</summary>
public long MinSizeToCompress { get; set; } = 1024; // 1 KB

/// <summary>Omitir tipos de contenido que ya incluyen compresión (JPEG, PNG, ZIP, etc.).</summary>
public bool SkipAlreadyCompressedTypes { get; set; } = true;

/// <summary>Tipos MIME adicionales a excluir de la compresión.</summary>
public IList<string> ExcludedContentTypes { get; set; } = [];

/// <summary>Si true, comprime todos los archivos sin importar el campo Compress del request.</summary>
public bool CompressAll { get; set; } = false;
}

Tabla de opciones

OpciónPor defectoDescripción
CompressionLevelOptimalFastest (rápido, menos compresión), Optimal (balance), SmallestSize (lento, mejor compresión)
MinSizeToCompress1024Archivos más pequeños no se comprimen (el overhead supera el beneficio)
SkipAlreadyCompressedTypestrueEvita recomprimir formatos que ya incluyen compresión interna
ExcludedContentTypes[]Tipos MIME adicionales a excluir manualmente
CompressAllfalseForzar compresión de todos los archivos ignorando el campo Compress del request

Tipos excluidos automáticamente

Cuando SkipAlreadyCompressedTypes = true, los siguientes tipos no se comprimen:

CategoríaTipos MIME excluidos
Imágenesimage/jpeg, image/png, image/gif, image/webp, image/avif
Videovideo/mp4, video/webm, video/avi, video/quicktime
Audioaudio/mpeg, audio/aac, audio/ogg, audio/flac
Archivos comprimidosapplication/zip, application/gzip, application/x-7z-compressed, application/x-rar-compressed
PDFapplication/pdf (incluye compresión Flate internamente)

Cómo funciona

En la subida

loading...

El middleware envuelve el stream en un GZipStream y agrega el metadato x-vali-compressed: true para que la descarga sepa que debe descomprimir.

En la descarga

loading...

Ejemplos de uso

Comprimir al subir (opt-in por request)

// Activar compresión solo para este archivo específico
var resultado = await storage.UploadAsync(new UploadRequest
{
Path = "backups/volcado-bd-2024-03.sql",
Content = sqlStream,
ContentType = "application/sql",
Compress = true // Opt-in explícito
}, ct);

Comprimir todos los archivos automáticamente

.UseCompression(c =>
{
c.CompressAll = true; // Comprimir todo
c.CompressionLevel = CompressionLevel.SmallestSize; // Máxima compresión
c.MinSizeToCompress = 512; // Incluso archivos pequeños
})

Excluir tipos adicionales de la compresión

.UseCompression(c =>
{
c.SkipAlreadyCompressedTypes = true;
c.ExcludedContentTypes =
[
"application/x-sqlite3", // SQLite ya tiene su propio formato
"application/octet-stream" // Datos binarios desconocidos
];
})

Descargar sin descompresión automática

// Obtener el archivo comprimido en bruto (para transferencia o inspección)
var resultado = await storage.DownloadAsync(new DownloadRequest
{
Path = "backups/volcado-bd.sql",
AutoDecompress = false // Obtener datos GZip sin descomprimir
}, ct);

// El stream contiene datos GZip — adecuado para guardar como .sql.gz
await using var archivoLocal = File.Create("volcado-bd.sql.gz");
await resultado.Value!.CopyToAsync(archivoLocal, ct);

Verificar si un archivo está comprimido

var meta = await storage.GetMetadataAsync("backups/volcado-bd.sql", ct);
if (meta.IsSuccess)
{
// Propiedad directa de FileMetadata
Console.WriteLine($"¿Comprimido? {meta.Value!.IsCompressed}");

// También disponible en metadatos personalizados
if (meta.Value.CustomMetadata.TryGetValue("x-vali-compressed", out var comprimido))
Console.WriteLine($"Metadato directo: {comprimido}");
}

Ahorro de espacio esperado por tipo de archivo

Tipo de archivoReducción típica¿Vale la pena comprimir?
Texto plano / CSV60–80%
JSON / XML70–85%
SQL dumps70–80%
HTML / JavaScript / CSS60–75%
Microsoft Word (.docx)10–20%Moderado
Imágenes JPEG / PNG0–5%No
PDF5–15%Poco beneficio
ZIP / RAR / 7z0–2%No
Video MP40–3%No

Cuándo usar y cuándo no usar compresión

Usa compresión para:

  • Archivos de texto grandes: logs, CSV, JSON, SQL dumps.
  • Backups de base de datos.
  • Archivos que se almacenan por tiempo prolongado y no se acceden frecuentemente.
  • Reducir costos de almacenamiento en proveedores que cobran por GB.

No uses compresión para:

  • Imágenes (JPEG, PNG, WebP), video y audio — ya están comprimidos.
  • Archivos que se acceden con alta frecuencia — el overhead de descompresión suma latencia.
  • Archivos pequeños (menos de 1 KB) — el overhead de GZip supera el ahorro.
Consejo

Usa CompressionLevel.Optimal para la mayoría de los casos de uso. SmallestSize puede reducir el tamaño un 5–10% adicional, pero puede ser 3–5 veces más lento. Resérvalo para archivos que se almacenan por largos períodos como backups de archivo.

Advertencia

La compresión debe ir antes del cifrado en el pipeline. Cifrar primero y luego intentar comprimir es ineficiente: los datos cifrados tienen alta entropía aleatoria y GZip prácticamente no los puede comprimir. El orden correcto en el pipeline es: UseCompression() seguido de UseEncryption().