Переименование файла/папки внутри ZIP-файла в Java?

StackOverflow https://stackoverflow.com/questions/847892

  •  21-08-2019
  •  | 
  •  

Вопрос

У меня есть zip-файл, содержащий структуру папок, например

  • основная папка/
    • подпапка1/
    • подпапка2/
    • подпапка3/
      • файл3.1
      • файл3.2

Я хотел бы переименовать папку main-folder скажем так versionXY внутри этого самого zip-файла с использованием Java.

Есть ли более простой способ, чем извлечь весь zip-файл и воссоздать новый, используя новые имена папок?

Это было полезно?

Решение

Zip — это формат архива, поэтому изменение обычно предполагает перезапись файла.

Некоторые особенности zip также мешают (zip полон «функций»).Как и центральный каталог в конце архива, каждому файлу компонента предшествует его имя.В Zip нет концепции каталогов — имена файлов — это просто строки, которые включают символы «/» (и подстроки, такие как «../».

Итак, вам действительно нужно скопировать файл, используя ZipInputStream и ZipOutputStream, переименовывая по ходу дела.Если вы действительно этого хотите, вы можете переписать файл на месте, выполнив собственную буферизацию.Этот процесс действительно приводит к повторному сжатию содержимого, поскольку стандартный API не имеет средств для получения данных в сжатой форме.

Другие советы

Я знаю, что вы спрашивали о Java, но я решил оставить заметку о .NET просто в архивных целях.

ДотНетЗип — это библиотека .NET для zip-файлов, позволяющая переименовывать записи.Как говорится в ответе Тома Хотина, каталоги не являются первоклассными объектами в метаданных zip-файла, и, как следствие, ни одна из известных мне zip-библиотек не предоставляет глагол «переименовать каталог».Но некоторые библиотеки позволяют переименовывать все записи, имена которых указывают на конкретный каталог, что дает желаемый результат.

В DotNetZip это будет выглядеть так:

 var regex = new Regex("/OldDirName/.*$");
 int renameCount= 0;
 using (ZipFile zip = ZipFile.Read(ExistingZipFile))
 {
    foreach (ZipEntry e in zip)
    {
        if (regex.IsMatch(e.FileName))
        {
            // rename here
            e.FileName = e.FileName.Replace("/OldDirName/", "/NewDirName/");
            renameCount++;
        }
    }
    if (renameCount > 0)
    {
        zip.Comment = String.Format("This archive has been modified. {0} entries have been renamed.", renameCount);
        // any changes to the entries are made permanent by Save()
        zip.Save();  // could also save to a new zip file here
    }
 }

Вы также можете добавлять или удалять записи внутри предложения using.

Если вы сохраняете в тот же файл, то DotNetZip перезаписывает только измененные метаданные — заголовки записей и записи центрального каталога для переименованных записей, что экономит время при работе с большими архивами.Если вы сохраните в новый файл или поток, все zip-данные будут записаны.

Я думаю, вы сможете найти помощь для этой задачи, используя Коммонс Сжатие, особенно ZipАрхивЗапись

Это делает трюк.Невероятно быстро, поскольку работает только с центральным каталогом, а не с файлами.

//  rezip( zipfile, "/main-folder", "/versionXY" );

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;


protected void rezip( String zipfile, String olddir, String newdir ) {

    Path zipFilePath = Paths.get( zipfile );
    try (FileSystem fs = FileSystems.newFileSystem( zipFilePath, null )) {
        Path oldpathInsideZipPath = fs.getPath( olddir );
        if( ! Files.exists( Paths.get( newdir ) ) )
            Files.createDirectory( Paths.get( newdir ) );

        if ( Files.exists( oldpathInsideZipPath, LinkOption.NOFOLLOW_LINKS ) ) {
            Files.walkFileTree(oldpathInsideZipPath, new SimpleFileVisitor<Path>() {
                 @Override
                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                     throws IOException
                 {
                     if( file.toString().indexOf( olddir ) > -1 ){
                         String a = file.toString().replaceAll( olddir, newdir );
                         Path b = fs.getPath( a );
                         if( ! Files.exists( b.getParent() ) ){
                             Files.createDirectories( b.getParent() );
                         }
                         Files.move( file, b, LinkOption.NOFOLLOW_LINKS );
                     }
                     return FileVisitResult.CONTINUE;
                 }
                 @Override
                 public FileVisitResult postVisitDirectory(Path dir, IOException e)
                     throws IOException
                 {
                     if (e == null) {
                         Files.delete(dir);
                         return FileVisitResult.CONTINUE;
                     } else {
                         // directory iteration failed
                         throw e;
                     }
                 }
             });
        }
        fs.close();
    } catch ( Exception e ) {
        e.printStackTrace();
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top