Gestión de archivos en Java: Conversión de MultipartFile y extracción de imágenes con Apache POI

En el desarrollo de aplicaciones web con Java, es común enfrentarse a la necesidad de procesar archivos Excel que contienen elemantos gráficos o transformar objetos entre diferentes representaciones de archivos, como File, arreglos de bytes y MultipartFile. A continuación, se detallan soluciones técnicas para estos escenarios.

Extracción de imágenes desde Excel mediante Apache POI

Cuando procesamos archivos de Excel (específicamente formatos legacy .xls), Apache POI permite acceder al patriarca del dibujo para recuperar imágenes incrustadas en celdas específicas.

// Inicialización del libro de trabajo según la extensión
InputStream excelStream = archivoEntrada.getInputStream();
Workbook libro;
if (nombreArchivo.endsWith(".xls")) {
    libro = new HSSFWorkbook(excelStream);
} else {
    libro = WorkbookFactory.create(excelStream);
}

// Acceso a una hoja específica
HSSFSheet hojaActiva = (HSSFSheet) libro.getSheetAt(0);
HSSFPatriarch patriarca = hojaActiva.getDrawingPatriarch();

if (patriarca != null) {
    List<HSSFShape> formas = patriarca.getChildren();
    for (HSSFShape forma : formas) {
        if (forma instanceof HSSFPicture) {
            HSSFPicture imagen = (HSSFPicture) forma;
            HSSFClientAnchor anclaje = (HSSFClientAnchor) imagen.getAnchor();
            HSSFPictureData datosImagen = imagen.getPictureData();

            // Validación de la posición de la imagen (Fila y Columna)
            int filaImagen = anclaje.getRow1();
            int columnaImagen = anclaje.getCol1();

            if (filaImagen == 5 && columnaImagen == 2) {
                byte[] contenidoImagen = datosImagen.getData();
                InputStream streamImagen = new ByteArrayInputStream(contenidoImagen);
                
                // Conversión de los datos de la imagen a MultipartFile para su almacenamiento
                MultipartFile archivoMultipart = new MockMultipartFile(
                    "foto_perfil.jpg", 
                    "foto_perfil.jpg", 
                    "image/jpeg", 
                    streamImagen
                );
                
                // Lógica de guardado mediante servicio de archivos
                servicioAlmacenamiento.guardar(archivoMultipart, "/ruta/destino");
            }
        }
    }
}

Conversión de arreglos de bytes a MultipartFile

Para transformar un byte[] en un objeto MultipartFile, la forma más eficiente es utilizar la clase MockMultipartFile proporcionada por el módulo de pruebas de Spring. Para ello, es necesario incluir la siguiente dependencia en el archivo pom.xml:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.x</version>
</dependency>

Implementación de la conversión:

byte[] bufferDatos = obtenerDatosBinarios();
InputStream inputBus = new ByteArrayInputStream(bufferDatos);
MultipartFile archivoConvertido = new MockMultipartFile(
    "nombre_archivo", 
    "archivo_original.dat", 
    MediaType.APPLICATION_OCTET_STREAM_VALUE, 
    inputBus
);

Transforamción de un objeto File a MultipartFile

Si se dispone de un archivo físico en el sistema (java.io.File) y se requiere convertirlo a MultipartFile para interactuar con controladores o servicios de Spring, se puede utilizar la librería commons-fileupload.

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

Método utilitario para la conversión:

public MultipartFile transformarFileAMultipart(File archivoOrigen) throws IOException {
    FileItem itemArchivo = new DiskFileItemFactory().createItem(
        "file", 
        Files.probeContentType(archivoOrigen.toPath()), 
        true, 
        archivoOrigen.getName()
    );

    try (InputStream in = new FileInputStream(archivoOrigen); 
         OutputStream out = itemArchivo.getOutputStream()) {
        IOUtils.copy(in, out);
    } catch (IOException e) {
        throw new RuntimeException("Error al copiar flujo de datos", e);
    }

    return new CommonsMultipartFile(itemArchivo);
}

Descompresión de paquetes ZIP en el servidor

El siguiente procedimiento permite recibir un MultipartFile que contiene un archivo comprimido, extraer su contenido y almacenarlo en un directorio temporal del servidor.

public void procesarYDescomprimirZip(MultipartFile zipEntrada, String rutaDestino) throws IOException {
    File directorioTemporal = new File(rutaDestino);
    if (!directorioTemporal.exists()) {
        directorioTemporal.mkdirs();
    }

    File archivoLocalZip = new File(directorioTemporal, zipEntrada.getOriginalFilename());
    zipEntrada.transferTo(archivoLocalZip);

    try (ZipFile zipFile = new ZipFile(archivoLocalZip, Charset.forName("UTF-8"))) {
        Enumeration<? extends ZipEntry> entradas = zipFile.entries();
        
        while (entradas.hasMoreElements()) {
            ZipEntry entrada = entradas.nextElement();
            File archivoSalida = new File(directorioTemporal, entrada.getName());

            if (entrada.isDirectory()) {
                archivoSalida.mkdirs();
            } else {
                if (!archivoSalida.getParentFile().exists()) {
                    archivoSalida.getParentFile().mkdirs();
                }

                try (InputStream is = zipFile.getInputStream(entrada);
                     FileOutputStream fos = new FileOutputStream(archivoSalida)) {
                    byte[] buffer = new byte[4096];
                    int leido;
                    while ((leido = is.read(buffer)) != -1) {
                        fos.write(buffer, 0, leido);
                    }
                }
            }
        }
    } finally {
        // Limpieza del archivo comprimido original después de la extracción
        if (archivoLocalZip.exists()) {
            archivoLocalZip.delete();
        }
    }
}

Etiquetas: java Apache POI Spring Framework MultipartFile File IO

Publicado el 7-19 08:40