无需在 Java 或 Python 中解压缩即可从 ZIP 存档中删除文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5244963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 10:12:03  来源:igfitidea点击:

Delete files from a ZIP archive without Decompressing in Java or maybe Python

javapythonzip

提问by SeanDav

Delete files from a ZIP archive without decompressing using Java (Preferred) or Python

从 ZIP 存档中删除文件而不使用 Java(首选)或 Python 解压缩

Hi,

你好,

I work with large ZIP files containing many hundreds of highly compressed text files. When I decompress the ZIP file it can take a while and easily consume up to 20 GB of diskspace. I would like to remove certain files from these ZIP files without having to decompress and recompress only the files I want.

我处理包含数百个高度压缩的文本文件的大型 ZIP 文件。当我解压缩 ZIP 文件时,它可能需要一段时间并且很容易消耗多达 20 GB 的磁盘空间。我想从这些 ZIP 文件中删除某些文件,而不必仅解压缩和重新压缩我想要的文件。

Of course it is certainly possible to do this the long way, but very inefficient.

当然,这样做当然是可能的,但效率很低。

I would prefer to do this in Java, but will consider Python

我更喜欢用 Java 来做这件事,但会考虑 Python

回答by Valen

I've found this on web

我在网上找到了这个

clean solution with only standard library, but I'm not sure whether it's included in android sdk, to be found.

只有标准库的干净解决方案,但我不确定它是否包含在 android sdk 中。

import java.util.*;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.*;
import java.nio.file.StandardCopyOption;
public class ZPFSDelete {
    public static void main(String [] args) throws Exception {

        /* Define ZIP File System Properies in HashMap */    
        Map<String, String> zip_properties = new HashMap<>(); 
        /* We want to read an existing ZIP File, so we set this to False */
        zip_properties.put("create", "false"); 

        /* Specify the path to the ZIP File that you want to read as a File System */
        URI zip_disk = URI.create("jar:file:/my_zip_file.zip");

        /* Create ZIP file System */
        try (FileSystem zipfs = FileSystems.newFileSystem(zip_disk, zip_properties)) {
            /* Get the Path inside ZIP File to delete the ZIP Entry */
            Path pathInZipfile = zipfs.getPath("source.sql");
            System.out.println("About to delete an entry from ZIP File" + pathInZipfile.toUri() ); 
            /* Execute Delete */
            Files.delete(pathInZipfile);
            System.out.println("File successfully deleted");   
        } 
    }
}

回答by Gabe

I don't have code to do this, but the basic idea is simple and should translate into almost any language the same way. The ZIP file layout is just a series of blocks that represent files (a header followed by the compressed data), finished off with a central directory that just contains all the metadata. Here's the process:

我没有这样做的代码,但基本思想很简单,应该以相同的方式翻译成几乎任何语言。ZIP 文件布局只是一系列代表文件的块(后跟压缩数据的标头),最后是一个仅包含所有元数据的中央目录。这是过程:

  1. Scan forward in the file until you find the first file you want to delete.
  2. Scan forward in the file until you find the first file you don'twant to delete oryou hit the central directory.
  3. Scan forward in the file until you find the first file you want to delete oryou hit the central directory.
  4. Copy all the data you found in step 3 back onto the data you skipped in step 2 until you find another file you want to delete oryou hit the central directory.
  5. Go to step 2 unless you've hit the central directory.
  6. Copy the central directory to where ever you left off copying, leaving out the entries for the deleted files and changing the offsets to reflect how much you moved each file.
  1. 在文件中向前扫描,直到找到要删除的第一个文件。
  2. 直到你找到你的第一个文件在文件中快进想要删除或者你打的中央目录。
  3. 在文件中向前扫描,直到找到要删除的第一个文件到达中央目录。
  4. 将您在第 3 步中找到的所有数据复制回您在第 2 步中跳过的数据,直到您找到另一个要删除的文件到达中央目录。
  5. 除非您点击了中央目录,否则请转到第 2 步。
  6. 将中央目录复制到您停止复制的位置,省略已删除文件的条目并更改偏移量以反映您移动了每个文件的量。

See http://en.wikipedia.org/wiki/ZIP_%28file_format%29for all the details on the ZIP file structures.

有关ZIP 文件结构的所有详细信息,请参阅http://en.wikipedia.org/wiki/ZIP_%28file_format%29

As bestsss suggests, you might want to perform the copying into another file, so as to prevent losing data in the event of a failure.

正如 bestsss 所建议的,您可能希望执行复制到另一个文件中,以防止在发生故障时丢失数据。

回答by SeanDav

Ok think I found a potential solution from www.javaer.org. It definitely deletes files inside the zip and I don't think it is decompressing anything. Here is the code:

好吧,我想我从 www.javaer.org 找到了一个潜在的解决方案。它肯定会删除 zip 中的文件,我认为它不会解压任何东西。这是代码:

public static void deleteZipEntry(File zipFile,
     String[] files) throws IOException {
       // get a temp file
File tempFile = File.createTempFile(zipFile.getName(), null);
       // delete it, otherwise you cannot rename your existing zip to it.
tempFile.delete();
tempFile.deleteOnExit();
boolean renameOk=zipFile.renameTo(tempFile);
if (!renameOk)
{
    throw new RuntimeException("could not rename the file "+zipFile.getAbsolutePath()+" to "+tempFile.getAbsolutePath());
}
byte[] buf = new byte[1024];

ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zipFile));

ZipEntry entry = zin.getNextEntry();
while (entry != null) {
    String name = entry.getName();
    boolean toBeDeleted = false;
    for (String f : files) {
        if (f.equals(name)) {
            toBeDeleted = true;
            break;
        }
    }
    if (!toBeDeleted) {
        // Add ZIP entry to output stream.
        zout.putNextEntry(new ZipEntry(name));
        // Transfer bytes from the ZIP file to the output file
        int len;
        while ((len = zin.read(buf)) > 0) {
            zout.write(buf, 0, len);
        }
    }
    entry = zin.getNextEntry();
}
// Close the streams        
zin.close();
// Compress the files
// Complete the ZIP file
zout.close();
tempFile.delete();

}

}

回答by Hardik

Yes it is possible for JAVA using library called TRUEZIP.

是的,JAVA 可以使用名为TRUEZIP 的库。

TrueZIP is a Java based virtual file system (VFS) which enables client applications to perform CRUD (Create, Read, Update, Delete) operations on archive files as if they were virtual directories, even with nested archive files in multithreaded environments

TrueZIP 是一种基于 Java 的虚拟文件系统 (VFS),它使客户端应用程序能够像虚拟目录一样对存档文件执行 CRUD(创建、读取、更新、删除)操作,即使在多线程环境中嵌套存档文件也是如此

see below link for more information https://truezip.java.net/

有关更多信息,参阅以下链接 https://truezip.java.net/

回答by D3_JMultiply

This might be old, but here is one way. And it does work because I use it constantly and it works fine.

这可能是旧的,但这是一种方法。它确实有效,因为我经常使用它并且效果很好。

public boolean deleteFile(String zip_dir, String subfile){

    delete(new File(zipdir, subfile));

}

private void delete(File file)
{
    if(file == null || !file.exists())
        return;
    if(file.isFile())
    {
        file.delete();
        return;
    }
    File children[] = file.listFiles();
    for(int i = 0; i < children.length; i++)
    {
        File child = children[i];
        if(child.isFile())
            child.delete();
        else
            delete(child);
    }

    file.delete();
}