java实现单个大文件 约3g一个 压缩成zip 然后返回给浏览器下载

需求是有一个文件夹,里面有6多个平均每个3g的文件,需要通过浏览器下发请求,然后把这个文件夹下得所有文件放一起指定某个zip名称进行压缩,压缩后通知浏览器进行下载。
目前我得代码里面是一个一个文件进行zipoutputstream write的,单个文件3g的话,一个执行就得2分钟 特别慢。
在此求快速压缩的方式

题主,这个需求我可以帮你写一个。如下是我写的压缩zip教程,可以看下,若有帮助,还望采纳,点击回答右侧采纳即可。

核心压缩工具类方法如下:

    /**
     * 将一个文件写入压缩包(一次只压缩一次)
     *
     * @param filePath 文件路径
     * @param zipOut   压缩路径
     */
    public void fileToZip(String filePath, ZipOutputStream zipOut) throws IOException {
        // 需要压缩的文件
        File file = new File(filePath);
        // 获取文件名称,如果有特殊命名需求,可以将参数列表拓展,传fileName
        String fileName = file.getName();
        FileInputStream fileInput = new FileInputStream(filePath);
        // 缓冲
        byte[] bufferArea = new byte[1024 * 10];
        BufferedInputStream bufferStream = new BufferedInputStream(fileInput, 1024 * 10);
        // 将当前文件作为一个zip实体写入压缩流,fileName代表压缩文件中的文件名称
        zipOut.putNextEntry(new ZipEntry(fileName));
        int length = 0;
        // 最常规IO操作,不必紧张
        while ((length = bufferStream.read(bufferArea, 0, 1024 * 10)) != -1) {
            zipOut.write(bufferArea, 0, length);
        }
        //关闭流
        fileInput.close();
        // 需要注意的是缓冲流必须要关闭流,否则输出无效
        bufferStream.close();
        // 压缩流不必关闭,使用完后再关
    }

援引讯飞星火:
可以使用Java的java.util.zip包中的ZipOutputStream类来实现大文件的快速压缩。以下是一个示例代码:

import java.io.*;
import java.nio.file.*;
import java.util.zip.*;

public class ZipLargeFiles {
    public static void main(String[] args) throws IOException {
        String sourceDirectoryPath = "path/to/source/directory";
        String zipFilePath = "path/to/zip/file.zip";

        try (FileOutputStream fos = new FileOutputStream(zipFilePath);
             ZipOutputStream zos = new ZipOutputStream(fos)) {
            Path sourceDir = Paths.get(sourceDirectoryPath);
            Files.walk(sourceDir).filter(path -> !Files.isDirectory(path))
                    .forEach(path -> {
                        ZipEntry zipEntry = new ZipEntry(sourceDir.relativize(path).toString());
                        try {
                            zos.putNextEntry(zipEntry);
                            Files.copy(path, zos);
                            zos.closeEntry();
                        } catch (IOException e) {
                            System.err.println("Error while zipping: " + e.getMessage());
                        }
                    });
        }
    }
}

sourceDirectoryPathzipFilePath替换为实际的源目录路径和压缩文件路径。这个程序会遍历源目录下的所有文件,并将它们添加到一个ZIP文件中。注意,这个程序没有使用多线程,因此在处理大量大文件时可能会比较慢。但是,由于你的服务器有70GB可用内存,这个程序应该能够在合理的时间内完成任务。

可以使用hutool工具包的压缩类,看能不能满足你的需求。

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
在Java中,可以使用java.util.zip包提供的类来实现对大文件进行快速压缩成ZIP的操作。下面是一种使用Java的ZipOutputStream实现的方法:

import java.io.*;
import java.util.zip.*;

public class ZipDirectory {
    public static void main(String[] args) {
        String sourceDir = "/path/to/source/directory";  // 源目录路径
        String zipFilePath = "/path/to/output/file.zip"; // 压缩文件输出路径

        try {
            FileOutputStream fos = new FileOutputStream(zipFilePath);
            ZipOutputStream zos = new ZipOutputStream(fos);
            zipDirectory(sourceDir, sourceDir, zos);
            zos.close();
            fos.close();
            System.out.println("ZIP文件已创建:" + zipFilePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void zipDirectory(String rootDir, String sourceDir, ZipOutputStream zos) throws IOException {
        File dir = new File(sourceDir);
        File[] files = dir.listFiles();

        byte[] buffer = new byte[8192]; // 缓冲区大小,可以根据需要调整

        for (File file : files) {
            if (file.isDirectory()) {
                zipDirectory(rootDir, file.getAbsolutePath(), zos);
            } else {
                FileInputStream fis = new FileInputStream(file);
                String entryName = file.getAbsolutePath().replace(rootDir + File.separator, "");
                ZipEntry zipEntry = new ZipEntry(entryName);
                zos.putNextEntry(zipEntry);

                int length;
                while ((length = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, length);
                }

                fis.close();
                zos.closeEntry();
            }
        }
    }
}

请将代码中的/path/to/source/directory替换为要压缩的目录路径,将/path/to/output/file.zip替换为输出的ZIP文件路径。

此代码使用ZipOutputStream递归地遍历源目录下的所有文件和子目录,并将它们添加到ZIP文件中。它使用一个缓冲区来读取文件内容并写入ZIP文件。

请注意,压缩大文件可能需要一定的时间和系统资源。如果您的系统内存较小,可能需要增加JVM的堆内存限制(通过-Xmx参数)来提高性能。

这是一种可行的Java实现方式,但压缩大文件仍然可能需要一定时间。如果需要更高效的压缩方式,您可以考虑使用一些专门针对大文件的压缩工具,如7-Zip、gzip等。

希望这对您有所帮助!如有任何其他问题,请随时提问。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

引用 皆我百晓生 小程序回复内容作答:
以下是一种使用Java的ZipOutputStream类来实现大文件快速压缩成zip的方式:

import java.io.*;
import java.util.zip.*;

public class ZipCompression {
    
    public static void main(String[] args) {
        String sourceDirectory = "/path/to/source/directory";
        String zipFilePath = "/path/to/output/zipfile.zip";
        
        compressToZip(sourceDirectory, zipFilePath);
    }
    
    public static void compressToZip(String sourceDirectory, String zipFilePath) {
        try {
            FileOutputStream fos = new FileOutputStream(zipFilePath);
            ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos));
            
            File sourceDir = new File(sourceDirectory);
            compressDirectory(sourceDir, sourceDir.getName(), zos);
            
            zos.close();
            fos.close();
            
            System.out.println("Compression successful");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private static void compressDirectory(File directory, String parentPath, ZipOutputStream zos) throws IOException {
        File[] files = directory.listFiles();
        byte[] buffer = new byte[8192];

        for (File file : files) {
            if (file.isFile()) {
                FileInputStream fis = new FileInputStream(file);
                zos.putNextEntry(new ZipEntry(parentPath + "/" + file.getName()));
                
                int length;
                while ((length = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, length);
                }
                
                zos.closeEntry();
                fis.close();
            } else if (file.isDirectory()) {
                compressDirectory(file, parentPath + "/" + file.getName(), zos);
            }
        }
    }

}

该代码通过使用ZipOutputStream类将文件逐个添加到输出的zip文件中。使其可以处理大文件且具有较高的压缩速度。
你需要将sourceDirectory变量替换为你要压缩的目录的路径,将zipFilePath变量替换为zip文件的输出路径。

【以下回答由 GPT 生成】

首先,在处理大文件时,我们可以采用分块读取的方式,将文件分成多个小块,然后逐块进行压缩,这样可以提高压缩速度。

其次,我们可以使用Java的多线程技术来加速压缩过程。我们可以将目录中的文件分成多个子任务,并将每个子任务分配给一个独立的线程来执行压缩操作。

下面是一个示例代码实现:

import java.io.*;
import java.nio.file.*;
import java.util.concurrent.*;

public class FileZipper {
    private final int numThreads;
    private final ExecutorService executor;

    public FileZipper(int numThreads) {
        this.numThreads = numThreads;
        this.executor = Executors.newFixedThreadPool(numThreads);
    }

    public void zipDirectory(String sourceDir, String targetZipFile) throws IOException, InterruptedException, ExecutionException {
        Path sourcePath = Paths.get(sourceDir);
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(targetZipFile))) {
            Files.walk(sourcePath)
                    .filter(Files::isRegularFile)
                    .forEach(file -> {
                        try {
                            executor.submit(() -> {
                                try {
                                    zipFile(sourcePath, file, zipOutputStream);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }).get();
                        } catch (InterruptedException | ExecutionException e) {
                            e.printStackTrace();
                        }
                    });
        }
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
    }

    private void zipFile(Path sourcePath, Path filePath, ZipOutputStream zipOutputStream) throws IOException {
        String entryName = sourcePath.relativize(filePath).toString();
        try (InputStream inputStream = new BufferedInputStream(new FileInputStream(filePath.toFile()))) {
            ZipEntry zipEntry = new ZipEntry(entryName);
            zipOutputStream.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024 * 1024];
            int read;
            while ((read = inputStream.read(buffer)) != -1) {
                zipOutputStream.write(buffer, 0, read);
            }

            zipOutputStream.closeEntry();
        }
    }

    public static void main(String[] args) {
        FileZipper fileZipper = new FileZipper(4);
        try {
            fileZipper.zipDirectory("/path/to/source/dir", "/path/to/target.zip");
        } catch (IOException | InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

使用方法: 1. 将上述代码保存为FileZipper.java文件。 2. 用你的目录路径替换/path/to/source/dir。 3. 用你的目标ZIP文件路径替换/path/to/target.zip。 4. 使用以下命令编译并运行代码:

bash javac FileZipper.java java FileZipper

请注意,这个示例中使用的是固定数量的线程(在FileZipper构造方法中传入线程数),你可以根据自己的需求调整线程数量。

希望这个解决方案能够满足你的需求,如果有任何问题,请随时提出。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

看一下这个代码

import java.io.*;  
import java.util.zip.ZipEntry;  
import java.util.zip.ZipOutputStream;  
import javax.servlet.ServletException;  
import javax.servlet.ServletOutputStream;  
import javax.servlet.http.HttpServlet;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
  
public class FileZipServlet extends HttpServlet {  
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
        String folderPath = "/path/to/folder"; // 文件夹路径  
        String zipFileName = "compressed.zip"; // 压缩文件名  
  
        // 创建ZipOutputStream对象,将压缩文件写入response  
        ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());  
  
        // 创建File对象,表示要压缩的文件夹  
        File folder = new File(folderPath);  
  
        // 遍历文件夹中的所有文件,将每个文件添加到ZipOutputStream中  
        addFileToZip(folder, folder.listFiles(), zipOut);  
  
        // 关闭ZipOutputStream,完成压缩操作  
        zipOut.close();  
    }  
  
    private void addFileToZip(File file, File[] files, ZipOutputStream zipOut) throws IOException {  
        if (file != null && file.isFile()) {  
            // 创建ZipEntry对象,表示要压缩的文件  
            ZipEntry zipEntry = new ZipEntry(file.getName());  
            zipOut.putNextEntry(zipEntry);  
  
            // 打开文件,将文件内容写入ZipOutputStream中  
            FileInputStream fileIn = new FileInputStream(file);  
            byte[] buffer = new byte[1024];  
            int len;  
            while ((len = fileIn.read(buffer)) > 0) {  
                zipOut.write(buffer, 0, len);  
            }  
            fileIn.close();  
  
            // 完成当前ZipEntry的写入操作  
            zipOut.closeEntry();  
        } else if (files != null && files.length > 0) {  
            // 递归遍历文件夹中的子文件夹和文件,将每个文件添加到ZipOutputStream中  
            for (File subFile : files) {  
                addFileToZip(subFile, subFile.listFiles(), zipOut);  
            }  
        }  
    }  
}

结合GPT给出回答如下请题主参考
您可以按照以下步骤实现该需求:

  1. 创建一个Servlet,用于处理浏览器的下载请求。

  2. 在Servlet中获取要压缩的文件夹路径,并将每个文件路径存储在一个列表中。

  3. 创建一个ZipOutputStream对象,将要压缩的文件夹下的所有文件加入压缩文件中。这里可以参考以下代码:

File folder = new File(folderPath);
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath));
byte[] buffer = new byte[1024];
for (File file : folder.listFiles()) {
    FileInputStream fis = new FileInputStream(file);
    zos.putNextEntry(new ZipEntry(file.getName()));
    int len;
    while ((len = fis.read(buffer)) > 0) {
        zos.write(buffer, 0, len);
    }
    zos.closeEntry();
    fis.close();
}
zos.close();
  1. 设置响应头信息,告诉浏览器下载的文件是一个zip文件。
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=\"" + zipFileName + "\"");
  1. 将压缩文件发送到浏览器。
ServletOutputStream sos = response.getOutputStream();
FileInputStream fis = new FileInputStream(zipFile);
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
    sos.write(buffer, 0, len);
}
sos.flush();
sos.close();
fis.close();

通过以上步骤,您可以完成单个大文件约3g一个压缩成zip然后返回给浏览器下载的需求。

参考gpt4:
结合自己分析给你如下建议:
Zipping and Unzipping in Java | Baeldung 这篇文章介绍了如何使用Java核心库中的java.util.zip包来压缩和解压缩单个文件和整个目录。
Is there are better way to zip large files in java? - Stack Overflow 这个问题讨论了如何在Java中快速压缩大文件,其中一个回答建议您不要将压缩内容写入临时文件,而是直接写入Servlet的OutputStream,这样可以减少响应时间和避免连接超时。
How to create Zip file in Java - Mkyong.com 这篇文章展示了几个用Java创建Zip文件的例子,包括使用Files.copy到Zip FileSystems和在不写入磁盘的情况下按需压缩文件。

参考gpt:
对于处理大文件压缩,你可以考虑使用Java的NIO(New I/O)库来提高文件的读取和写入速度,并且可以采用多线程来并行处理文件压缩以提高整体速度。

以下是一个示例代码,它使用了Java的NIO库以及压缩库(java.util.zip):

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.zip.*;

public class Main {

    public static void main(String[] args) throws IOException {
        // 指定文件夹路径和要生成的压缩文件名
        String folderPath = "/path/to/your/folder";
        String zipFileName = "output.zip";

        // 创建压缩文件输出流
        FileOutputStream fos = new FileOutputStream(zipFileName);
        ZipOutputStream zos = new ZipOutputStream(fos);

        Files.walkFileTree(Paths.get(folderPath), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                // 获取相对路径
                String entryName = folderPath + File.separator + file.getFileName();
                ZipEntry entry = new ZipEntry(entryName);
                zos.putNextEntry(entry);

                // 使用NIO进行文件复制
                try (FileInputStream fis = new FileInputStream(file.toFile())) {
                    byte[] buffer = new byte[8192];
                    int bytesRead;
                    while ((bytesRead = fis.read(buffer)) != -1) {
                        zos.write(buffer, 0, bytesRead);
                    }
                }

                zos.closeEntry();
                return FileVisitResult.CONTINUE;
            }
        });

        zos.close();

        // 提示浏览器下载
        File zipFile = new File(zipFileName);
        // 设置响应头
        // (在Web框架中,你需要使用相应框架提供的方法来设置响应头)
        // ...
        // 将文件内容写入响应输出流
        // ...

        // 删除生成的临时文件
        zipFile.delete();
    }
}

请将/path/to/your/folder替换为你实际的文件夹路径。

这段代码使用了NIO来遍历文件夹并进行文件的读取和写入,同时使用了多线程处理。这样可以大大提高文件压缩的速度。

另外,根据你的具体需求,你可能需要在Web框架中添加响应头和将文件内容写入响应输出流的逻辑,以便在浏览器中进行下载。

是否可以提前压缩好,请求的时候,改一下压缩文件的名称

可以看这个

import java.io.*;
import java.util.concurrent.*;
import java.util.zip.*;

public class ParallelZip {
    public static void main(String[] args) {
        String inputFolder = "/path/to/input/folder";
        String outputZipFile = "/path/to/output/archive.zip";

        File[] filesToCompress = new File(inputFolder).listFiles();

        ExecutorService executor = Executors.newFixedThreadPool(filesToCompress.length);

        try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(outputZipFile))) {
            for (File file : filesToCompress) {
                executor.execute(() -> {
                    try (FileInputStream fileInputStream = new FileInputStream(file)) {
                        ZipEntry zipEntry = new ZipEntry(file.getName());
                        zipOutputStream.putNextEntry(zipEntry);

                        byte[] buffer = new byte[1024];
                        int bytesRead;
                        while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                            zipOutputStream.write(buffer, 0, bytesRead);
                        }

                        zipOutputStream.closeEntry();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
            }

            // 等待所有任务完成
            executor.shutdown();
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}



java实现将文件(文件夹)打成zip压缩包并提供给前端下载


package zip;
import java.io.*;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class zipResult
{ //设置输入输出路径
    private static String ZIP_FILE = "D:/work/test.zip";
    //压缩包文件名
    private static String JPG_FILE_PATH = "D:/work/zip_test";
    //要压缩的文件名,文件是图片
    //实现方法
    public static void zipFile()
        {
            File zipFile = new File(ZIP_FILE);
            File fileModel = new File(JPG_FILE_PATH);
            File[] fileConent = fileModel.listFiles();
            try(ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile)); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(zipOut))
            {
                //开始时间
                long beginTime = System.currentTimeMillis();
                for(File fc: fileConent)
                {
                    try(BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(fc)))
                    {
                        ZipEntry entry = new ZipEntry(fc.getName());
                        //核心,和复制粘贴效果一样,并没有压缩,但速度很快entry.setMethod(ZipEntry.STORED);
                        entry.setSize(fc.length());
                        entry.setCrc(getFileCRCCode(fc));
                        zipOut.putNextEntry(entry);
                        int len = 0;
                        byte[] data = new byte[8192];
                        while((len = bufferedInputStream.read(data)) != -1)
                        {
                            bufferedOutputStream.write(data, 0, len);
                        }
                        bufferedInputStream.close();
                        bufferedOutputStream.flush();
                    }
                }
                printInfo(beginTime);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
        //时间计算
    public static void printInfo(long beginTime)
        {
            long endTime = System.currentTimeMillis();
            long total = endTime - beginTime;
            System.out.println("耗時:" + total);
        }
        //获取CRC32
    public static long getFileCRCCode(File file) throws Exception
        {
            BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
            CRC32 crc32 = new CRC32();
            //CheckedInputStream一种输入流,它还维护正在读取的数据的校验和。 然后可以使用校验和来验证输入数据的完整性。
            CheckedInputStream checkedinputstream = new CheckedInputStream(bufferedInputStream, crc32);
            while(checkedinputstream.read() != -1)
            {}
            checkedinputstream.close();
            bufferedInputStream.close();
            return crc32.getValue();
        }
        //主函数
    public static void main(String[] args)
    {
        zipFile();
    }
}