删除ZIP存档中的文件,而无需在Java或Python中解压缩

时间:2011-03-09 11:13:47

标签: java python zip

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

进行解压缩

您好,

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

当然,长期以来可以做到这一点,但效率非常低。

我更愿意在Java中这样做,但会考虑Python

5 个答案:

答案 0 :(得分:3)

I've found this on web

仅使用标准库的干净解决方案,但我不确定它是否包含在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");   
        } 
    }
}

答案 1 :(得分:2)

我没有代码可以做到这一点,但基本的想法很简单,几乎可以翻译成任何语言。 ZIP文件布局只是一系列代表文件的块(标题后跟压缩数据),最后是一个只包含所有元数据的中心目录。这是过程:

  1. 在文件中向前扫描,直至找到要删除的第一个文件。
  2. 在文件中向前扫描,直至找到想要删除的第一个文件,即可点击中央目录。
  3. 在文件中向前扫描,直至找到要删除的第一个文件,即可点击中央目录。
  4. 将您在步骤3中找到的所有数据复制回您在步骤2中跳过的数据,直至找到要删除的其他文件您点击中央目录。
  5. 除非您点击中央目录,否则请转到第2步。
  6. 将中央目录复制到您不复制的位置,省略已删除文件的条目,并更改偏移量以反映每个文件的移动量。
  7. 有关ZIP文件结构的所有详细信息,请参阅http://en.wikipedia.org/wiki/ZIP_%28file_format%29

    最好的建议是,您可能希望将复制复制到另一个文件中,以防止在发生故障时丢失数据。

答案 2 :(得分:0)

好的,我想从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();

}

答案 3 :(得分:0)

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

  

TrueZIP是一个基于Java的虚拟文件系统(VFS),它支持客户端   用于执行CRUD(创建,读取,更新,删除)操作的应用程序   在归档文件上,就像它们是虚拟目录一样,即使是嵌套的   多线程环境中的归档文件

请参阅以下链接以获取更多信息 https://truezip.java.net/

答案 4 :(得分:-4)

这可能是旧的,但这是一种方式。它确实有效,因为我经常使用它并且工作正常。

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();
}