Paquete compress en Go
El paquete compress en Go proporciona varios subpaquetes para trabajar con diferentes algoritmos de compresión y formatos de archivo comprimido. Este documento explora en detalle cada subpaquete con ejemplos prácticos.
1. compress/bzip2
1.1 Lectura de Archivos bzip2
func ejemploLecturaBzip2() error {
// Abrir archivo bzip2
archivo, err := os.Open("datos.bz2")
if err != nil {
return fmt.Errorf("error abriendo archivo: %w", err)
}
defer archivo.Close()
// Crear lector bzip2
reader := bzip2.NewReader(archivo)
// Leer contenido descomprimido
contenido, err := io.ReadAll(reader)
if (err != nil) {
return fmt.Errorf("error leyendo contenido: %w", err)
}
fmt.Printf("Contenido descomprimido: %s\n", contenido)
return nil
}
1.2 Procesamiento por Bloques
func procesarBzip2PorBloques(filename string, tamañoBloque int) error {
archivo, err := os.Open(filename)
if err != nil {
return err
}
defer archivo.Close()
reader := bzip2.NewReader(archivo)
buffer := make([]byte, tamañoBloque)
for {
n, err := reader.Read(buffer)
if err == io.EOF {
break
}
if err != nil {
return err
}
// Procesar el bloque leído
procesarBloque(buffer[:n])
}
return nil
}
func procesarBloque(datos []byte) {
// Implementar procesamiento específico
}
2. compress/flate
2.1 Compresión Básica
func comprimirDatos(datos []byte) ([]byte, error) {
var buf bytes.Buffer
// Crear escritor con compresión
writer, err := flate.NewWriter(&buf, flate.BestCompression)
if err != nil {
return nil, err
}
// Escribir datos
if _, err := writer.Write(datos); err != nil {
return nil, err
}
// Cerrar para asegurar que todos los datos se escriban
if err := writer.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
2.2 Descompresión con Diccionario
func descomprimirConDiccionario(datos []byte, diccionario []byte) ([]byte, error) {
// Crear reader con diccionario
reader := flate.NewReaderDict(bytes.NewReader(datos), diccionario)
defer reader.Close()
// Leer datos descomprimidos
return io.ReadAll(reader)
}
3. compress/gzip
3.1 Compresión de Archivos
func comprimirArchivo(entrada, salida string) error {
// Abrir archivo de entrada
in, err := os.Open(entrada)
if err != nil {
return err
}
defer in.Close()
// Crear archivo de salida
out, err := os.Create(salida)
if err != nil {
return err
}
defer out.Close()
// Crear escritor gzip
gw := gzip.NewWriter(out)
defer gw.Close()
// Configurar metadatos
gw.Name = filepath.Base(entrada)
gw.ModTime = time.Now()
gw.Comment = "Comprimido con Go"
// Copiar datos
if _, err := io.Copy(gw, in); err != nil {
return err
}
return nil
}
3.2 Lectura de Archivos Gzip con Metadata
func leerArchivoGzip(filename string) error {
// Abrir archivo
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// Crear lector gzip
gr, err := gzip.NewReader(file)
if err != nil {
return err
}
defer gr.Close()
// Mostrar metadata
fmt.Printf("Nombre original: %s\n", gr.Name)
fmt.Printf("Fecha modificación: %v\n", gr.ModTime)
fmt.Printf("Comentario: %s\n", gr.Comment)
// Leer contenido
contenido, err := io.ReadAll(gr)
if err != nil {
return err
}
fmt.Printf("Contenido: %s\n", contenido)
return nil
}
4. compress/zlib
4.1 Compresión en Memoria
func comprimirZlib(datos []byte, nivel int) ([]byte, error) {
var buf bytes.Buffer
// Crear escritor con nivel específico
writer, err := zlib.NewWriterLevel(&buf, nivel)
if err != nil {
return nil, err
}
// Escribir datos
if _, err := writer.Write(datos); err != nil {
return nil, err
}
if err := writer.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
4.2 Compresión con Progress Bar
func comprimirConProgreso(entrada, salida string) error {
// Abrir archivo de entrada
in, err := os.Open(entrada)
if err != nil {
return err
}
defer in.Close()
// Obtener tamaño del archivo
info, err := in.Stat()
if err != nil {
return err
}
// Crear archivo de salida
out, err := os.Create(salida)
if err != nil {
return err
}
defer out.Close()
// Crear writer zlib
zw := zlib.NewWriter(out)
defer zw.Close()
// Crear progress bar
bar := progressbar.DefaultBytes(
info.Size(),
"Comprimiendo",
)
// Copiar datos con progreso
if _, err := io.Copy(io.MultiWriter(zw, bar), in); err != nil {
return err
}
return nil
}
5. Utilidades y Helpers
5.1 Detector de Formato
func detectarFormatoCompresion(datos []byte) string {
if len(datos) < 4 {
return "desconocido"
}
// Detectar formato basado en magic numbers
switch {
case bytes.HasPrefix(datos, []byte{0x1f, 0x8b}):
return "gzip"
case bytes.HasPrefix(datos, []byte{0x42, 0x5a, 0x68}):
return "bzip2"
case bytes.HasPrefix(datos, []byte{0x78, 0x01}):
return "zlib"
default:
return "desconocido"
}
}
5.2 Compresor Universal
type CompresorConfig struct {
Formato string
Nivel int
Dictionary []byte
}
func ComprimirDatos(datos []byte, config CompresorConfig) ([]byte, error) {
var buf bytes.Buffer
switch config.Formato {
case "gzip":
w, err := gzip.NewWriterLevel(&buf, config.Nivel)
if err != nil {
return nil, err
}
defer w.Close()
_, err = w.Write(datos)
return buf.Bytes(), err
case "zlib":
w, err := zlib.NewWriterLevel(&buf, config.Nivel)
if err != nil {
return nil, err
}
defer w.Close()
_, err = w.Write(datos)
return buf.Bytes(), err
// Agregar más formatos según sea necesario
default:
return nil, fmt.Errorf("formato no soportado: %s", config.Formato)
}
}
6. Mejores Prácticas
- Manejo de Recursos
- Siempre cerrar readers y writers
- Usar
deferpara garantizar el cierre - Manejar errores apropiadamente
- Optimización
- Elegir el nivel de compresión adecuado
- Usar buffers de tamaño apropiado
- Considerar el uso de goroutines para compresión paralela
- Seguridad
- Validar tamaños de entrada
- Establecer límites de memoria
- Verificar integridad de datos comprimidos