Удалить файлы из ZIP-архива без распаковки в Java или, возможно, Python - PullRequest
4 голосов
/ 09 марта 2011

Удаление файлов из ZIP-архива без распаковки с использованием Java (Preferred) или Python

Привет,

Я работаю с большими ZIP-файлами, содержащими многие сотни сильно сжатых текстовых файлов.Когда я распаковываю ZIP-файл, это может занять некоторое время и легко занять до 20 ГБ дискового пространства.Я хотел бы удалить некоторые файлы из этих ZIP-файлов без необходимости распаковывать и повторно сжимать только те файлы, которые мне нужны.

Конечно, это, безусловно, возможно сделать долго, но очень неэффективно.

Я бы предпочел сделать это на Java, но рассмотрим Python

Ответы [ 5 ]

3 голосов
/ 18 марта 2016

Я нашел это в Интернете

чистое решение с только стандартной библиотекой, но я не уверен, что оно включено в 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");   
        } 
    }
}
2 голосов
/ 09 марта 2011

У меня нет кода для этого, но основная идея проста и должна переводиться практически на любой язык таким же образом. Структура файла ZIP представляет собой просто последовательность блоков, представляющих файлы (заголовок, за которым следуют сжатые данные), завершается центральным каталогом, который содержит все метаданные. Вот процесс:

  1. Сканируйте файл вперед, пока не найдете первый файл, который хотите удалить.
  2. Сканирование вперед в файле, пока не будет найден первый файл, который не хотите удалить или , попавший в центральный каталог.
  3. Сканирование вперед в файле, пока не будет найден первый файл, который вы хотите удалить или , попавший в центральный каталог.
  4. Скопируйте все данные, которые вы нашли на шаге 3, обратно в данные, которые вы пропустили на шаге 2, пока не найдете другой файл, который хотите удалить или , попадающий в центральный каталог.
  5. Переходите к шагу 2, если вы не нажали центральный каталог.
  6. Скопируйте центральный каталог туда, где вы когда-либо прекращали копирование, оставляя записи для удаленных файлов и изменяя смещения, чтобы отразить, насколько вы переместили каждый файл.

См. http://en.wikipedia.org/wiki/ZIP_%28file_format%29 для получения подробной информации о структурах файлов ZIP.

Как предполагает bestsss, вы можете выполнить копирование в другой файл, чтобы предотвратить потерю данных в случае сбоя.

0 голосов
/ 29 июня 2016

Да, для JAVA возможно использование библиотеки под названием TRUEZIP .

TrueZIP - виртуальная файловая система (VFS) на основе Java, которая позволяет клиенту приложения для выполнения операций CRUD (создание, чтение, обновление, удаление) на архивные файлы, как если бы они были виртуальными каталогами, даже с вложенными архивные файлы в многопоточных средах

см. Ссылку ниже для получения дополнительной информации https://truezip.java.net/

0 голосов
/ 30 октября 2011

Это может быть старым, но вот один из способов. И он работает, потому что я использую его постоянно, и он отлично работает.

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();
}
0 голосов
/ 09 марта 2011

Хорошо, думаю, я нашел потенциальное решение от www.javaer.org.Это определенно удаляет файлы внутри почтового индекса, и я не думаю, что это что-то распаковывает.Вот код:

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

}

...