kejhy93 / metro-timetable

0 stars 0 forks source link

Download and extract ZIP #14

Open kejhy93 opened 2 months ago

kejhy93 commented 1 month ago

To download a ZIP file using a Spring Boot application, you typically need to:

  1. Create a REST Controller that returns the ZIP file.
  2. Compress the desired content into a ZIP format.
  3. Send the ZIP file as a response to the client.

Here is a step-by-step guide:

1. Add Required Dependencies

First, make sure you have the necessary dependencies for a Spring Boot web application in your pom.xml (for Maven) or build.gradle (for Gradle).

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. Create a REST Controller

In the controller, you will create a method that:

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
public class ZipDownloadController {

    @GetMapping("/download-zip")
    public ResponseEntity<byte[]> downloadZip() throws IOException {
        // Prepare the in-memory stream for the ZIP file
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream);

        // Add files/content to the ZIP
        ZipEntry zipEntry = new ZipEntry("file1.txt");
        zipOutputStream.putNextEntry(zipEntry);
        zipOutputStream.write("This is the content of file1.".getBytes());
        zipOutputStream.closeEntry();

        zipEntry = new ZipEntry("file2.txt");
        zipOutputStream.putNextEntry(zipEntry);
        zipOutputStream.write("This is the content of file2.".getBytes());
        zipOutputStream.closeEntry();

        // Close the ZIP stream
        zipOutputStream.close();

        // Prepare the response
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attachment; filename=example.zip");

        return new ResponseEntity<>(byteArrayOutputStream.toByteArray(), headers, HttpStatus.OK);
    }
}

Explanation:

  1. ByteArrayOutputStream: This stream holds the in-memory ZIP file.
  2. ZipOutputStream: Used to write multiple entries (files) into the ZIP.
  3. ResponseEntity: Sends the ZIP file as a response, with appropriate headers to trigger a file download.

3. Test the Endpoint

Start your Spring Boot application and navigate to http://localhost:8080/download-zip. This will download the ZIP file with file1.txt and file2.txt inside it.

If you're running this on a different port, make sure to adjust the URL accordingly.

kejhy93 commented 1 month ago

To download a ZIP file from the internet and extract it in-memory (i.e., without saving it to the file system), you can achieve this by following these steps:

  1. Download the ZIP file as a stream.
  2. Use a ZipInputStream to read and extract the contents.
  3. Process the extracted files in memory, without writing them to disk.

Here’s a solution using Spring Boot and Java standard libraries for handling the process entirely in memory.

Example Code

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

@RestController
public class ZipInMemoryController {

    @GetMapping("/download-and-extract-inmemory")
    public String downloadAndExtractInMemory() {
        // URL of the ZIP file
        String zipFileUrl = "https://example.com/sample.zip";  // Replace with actual URL

        try {
            // 1. Download ZIP file as InputStream
            InputStream zipInputStream = downloadZipFileAsStream(zipFileUrl);

            // 2. Extract the ZIP file in-memory
            extractZipInMemory(zipInputStream);

            return "ZIP file downloaded and extracted in-memory successfully!";
        } catch (IOException e) {
            e.printStackTrace();
            return "Failed to download or extract the ZIP file in-memory.";
        }
    }

    // Method to download the ZIP file as an InputStream
    private InputStream downloadZipFileAsStream(String zipFileUrl) throws IOException {
        URL url = new URL(zipFileUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setDoOutput(true);
        connection.connect();

        return connection.getInputStream();
    }

    // Method to extract the ZIP file in-memory
    private void extractZipInMemory(InputStream inputStream) throws IOException {
        try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
            ZipEntry entry;
            while ((entry = zipInputStream.getNextEntry()) != null) {
                System.out.println("Extracting: " + entry.getName());

                // If the entry is a file, read the content
                if (!entry.isDirectory()) {
                    ByteArrayOutputStream fileOutputStream = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = zipInputStream.read(buffer)) > 0) {
                        fileOutputStream.write(buffer, 0, length);
                    }

                    // Here you have the file content in memory as a byte array
                    byte[] fileContent = fileOutputStream.toByteArray();
                    System.out.println("File size: " + fileContent.length + " bytes");

                    // You can now handle the file content as needed (e.g., store in database, process, etc.)
                }

                zipInputStream.closeEntry();
            }
        }
    }
}

Explanation:

  1. Downloading the ZIP file:

    • The downloadZipFileAsStream method uses HttpURLConnection to download the ZIP file from the internet and returns an InputStream.
  2. Extracting ZIP in memory:

    • The ZipInputStream is used to process the ZIP file stream.
    • Each ZipEntry is processed in-memory (read directly from the ZipInputStream without writing to disk).
    • The content of each file is extracted to a ByteArrayOutputStream, which keeps the file contents in memory as a byte array.
  3. Processing the files:

    • You can handle the file content (which is stored in a byte array) as needed, such as storing it in a database, processing it further, or sending it to another service.

Key Points:

You can use this approach when working with ZIP files stored on the internet that need to be downloaded and processed without touching the filesystem.