Search code examples
javaazureazure-blob-storageblob

azure blob ziping files


I am trying to zip files in Azure blob. I can create a zip file with the normal zip method but to improve performance when I try using completable future I get an exception.

    try (ZipOutputStream zipStream = new ZipOutputStream(outputStream)) {
            List<CompletableFuture<Void>> futures = new ArrayList<>();

            for (String singleFileName : fileNames) {
                String singleFilePath = azureFilePath + "/" + singleFileName.trim();
                BlobClient blobClient = blobContainerClient.getBlobClient(singleFilePath);

                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try (ByteArrayOutputStream fileOutputStream = new ByteArrayOutputStream()) {
                        if (blobClient.exists()) {
                            // Download the file to a separate output stream
                            blobClient.download(fileOutputStream);

                            // Add the file to the zip stream
                            zipStream.putNextEntry(new ZipEntry(singleFileName));
                            zipStream.write(fileOutputStream.toByteArray());
                          // zipStream.closeEntry();
                        } else {
                            throw new RuntimeException("File not found: " + singleFilePath);
                        }
                    } catch (IOException e) {
                        throw new RuntimeException("Error processing file: " + singleFileName, e);
                    }finally {
                        try {
                            zipStream.closeEntry();
                        } catch (IOException e) {
                            // Handle any potential exception when closing the zip entry
                            e.printStackTrace();
                        }
                    }
                });

                futures.add(future);
            }
            CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
            allOf.join();
        }

        // Upload the zip file to the same location
        BlobClient zipFileClient = blobContainerClient.getBlobClient(azureFilePath + "/" + zipFileName);
        zipFileClient.upload(new ByteArrayInputStream(outputStream.toByteArray()), outputStream.size(),true);

Throws exception at zipStream.write(fileOutputStream.toByteArray());

java.util.zip.ZipException: no current ZIP entry
at java.base/java.util.zip.ZipOutputStream.write(ZipOutputStream.java:343) ~[na:na]
at java.base/java.io.FilterOutputStream.write(FilterOutputStream.java:108) ~[na:na]
at main.java.com.azure.filezip.ApiControllerzip.lambda$uploadZip$0(ApiControllerzip.java:78) ~[classes/:na]

Any suggestions?


Solution

  • java.util.zip.ZipException: no current ZIP entry

    The above error occurred when the code tried to write to the ZipOutputStream before creating a new entry with putNextEntry().

    To fix this, the write() method should be moved inside the CompletableFuture, after the call to putNextEntry().

    Code:

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.concurrent.CompletableFuture;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipOutputStream;
    import java.io.ByteArrayOutputStream;
    
    import com.azure.storage.blob.BlobServiceClientBuilder;
    import com.azure.storage.blob.BlobServiceClient;
    import com.azure.storage.blob.BlobContainerClient;
    import com.azure.storage.blob.BlobClient;
    
    public class App {
    
        public static void main(String[] args) {
    
            String connectionString = "xxxx";
            String containerName = "test";
            String azureFilePath = "sample";
            String zipFileName = "output.zip";
    
            List<String> fileNames = Arrays.asList("demo.pdf","jgs.html","test.jpg");
            zipFilesInBlob(connectionString, containerName, azureFilePath, zipFileName, fileNames);
            System.out.println("Zip operation completed successfully.");
        }
    
        public static void zipFilesInBlob(String connectionString, String containerName, String azureFilePath,
                String zipFileName, List<String> fileNames) {
            BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().connectionString(connectionString)
                    .buildClient();
            BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient(containerName);
    
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    
            try (ZipOutputStream zipStream = new ZipOutputStream(outputStream)) {
                List<CompletableFuture<Void>> futures = new ArrayList<>();
    
                for (String singleFileName : fileNames) {
                    String singleFilePath = azureFilePath + "/" + singleFileName.trim();
                    final BlobClient blobClient = blobContainerClient.getBlobClient(singleFilePath);
    
                    final String finalSingleFileName = singleFileName;
                    final String finalSingleFilepath = singleFilePath;
    
                    CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
                        @Override
                        public void run() {
                            try (ByteArrayOutputStream fileOutputStream = new ByteArrayOutputStream()) {
                                if (blobClient.exists()) {
                                    blobClient.download(fileOutputStream);
                                    zipStream.putNextEntry(new ZipEntry(finalSingleFileName));
                                    zipStream.write(fileOutputStream.toByteArray());
                                    zipStream.closeEntry();
                                } else {
                                    throw new RuntimeException("File not found: " + finalSingleFilepath);
                                }
                            } catch (IOException e) {
                                throw new RuntimeException("Error processing file: " + finalSingleFileName, e);
                            }
                        }
                    });
    
                    futures.add(future);
                }
    
                CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
                allOf.join();
            } catch (IOException e) {
                throw new RuntimeException("Error creating zip file", e);
            }
    
            BlobClient zipFileClient = blobContainerClient.getBlobClient(azureFilePath + "/" + zipFileName);
            zipFileClient.upload(new ByteArrayInputStream(outputStream.toByteArray()), outputStream.size(), true);
        }
    }
    

    The above code creates a ZipOutputStream and loops through the list of file names, downloading each file from Azure Storage and adding it to the zip stream. Finally, it uploads the zip file to Azure Storage.

    Output:

    Zip operation completed successfully.
    

    Portal:

    Zip files in Azure Storage

    Reference:

    ZipOutputStream (Java Platform)