Pergunta

Eu tenho um arquivo zip que contém uma estrutura de pastas como

  • main-pasta /
    • SubFolder1 /
    • Subpasta2 /
    • subFolder3 /
      • file3.1
      • file3.2

Eu gostaria de mudar o nome pasta main-folder para digamos versionXY interior que muito arquivo zip usando Java.

Existe uma maneira mais simples do que extrair todo o arquivo zip e recriar um novo usando os nomes nova pasta?

Foi útil?

Solução

Zip é um formato de arquivo, assim mutação geralmente envolve reescrever o arquivo.

Algumas características particulares de zip também ficar no caminho (zip está cheio de "características"). Bem como o diretório central no final do arquivo, cada arquivo componente é precedida pelo nome do arquivo. Zip não tem um conceito de diretórios - nomes de arquivos são apenas cordas que acontecem para incluir caracteres "/" (e substrings como" ../".

Então, você realmente precisa para copiar o arquivo usando ZipInputStream e ZipOutputStream, renomeando que você vá. Se você realmente quiser você pode reescrever o arquivo no lugar fazendo seu próprio buffering. O processo faz com que o conteúdo a ser novamente comprimida como a API padrão tem nenhum meio de obtenção dos dados em forma comprimida.

Outras dicas

Eu sei que você perguntou sobre Java, mas apenas para fins de arquivamento eu pensei que iria contribuir com uma nota sobre .NET.

DotNetZip é uma biblioteca NET para zip arquivos que permite renomear de entradas. Como estados de resposta de Tom Hawtin, diretórios não são entidades de primeira classe nos metadados do arquivo zip, e como resultado, há bibliotecas zip que eu conheço expor um "diretório de renomeação" verbo. Mas algumas bibliotecas permitem que você para renomear todas as entradas que têm nomes que indicam um diretório específico, o que lhe dá o resultado desejado.

Em DotNetZip, ele ficaria assim:

 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
    }
 }

Você também pode adicionar ou remover entradas, dentro da cláusula usando.

Se você salvar para o mesmo arquivo, em seguida, DotNetZip reescreve apenas o mudada metadados - os cabeçalhos de entrada e os registros de diretório central para entradas renomeados, o que economiza tempo com grandes arquivos. Se você salvar para um novo arquivo ou fluxo, então todos os dados zip é escrita.

Eu acho que você vai ser capaz de encontrar ajuda para esta tarefa usando o Commons Compress, especialmente ZipArchiveEntry

Esta é fazer o truque. Super rápido, uma vez que funciona apenas no diretório central e não os arquivos.

//  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();
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top