在Java中重命名Zip文件中的文件/文件夹?

在Java中重命名Zip文件中的文件/文件夹?,java,zip,rename,Java,Zip,Rename,我有一个包含如下文件夹结构的zip文件 主文件夹/ 子文件夹1/ 子文件夹2/ 子文件夹3/ 文件3.1 文件3.2 我想将文件夹main folder重命名为使用Java的zip文件中的versionXY 有没有比提取整个zip文件并使用新文件夹名称重新创建一个新文件更简单的方法?我认为您可以使用,特别是zip是一种存档格式,因此,变异通常涉及重写文件 zip的一些特殊功能也会妨碍它(zip充满了“功能”)。与归档文件末尾的中心目录一样,每个组件文件前面都有其文件名。Zip没有目录

我有一个包含如下文件夹结构的zip文件

  • 主文件夹/
    • 子文件夹1/
    • 子文件夹2/
    • 子文件夹3/
      • 文件3.1
      • 文件3.2
我想将文件夹
main folder
重命名为使用Java的zip文件中的
versionXY


有没有比提取整个zip文件并使用新文件夹名称重新创建一个新文件更简单的方法?

我认为您可以使用,特别是zip是一种存档格式,因此,变异通常涉及重写文件

zip的一些特殊功能也会妨碍它(zip充满了“功能”)。与归档文件末尾的中心目录一样,每个组件文件前面都有其文件名。Zip没有目录的概念-文件名只是碰巧包含
“/”
字符的字符串(以及子字符串,如
。/”

因此,您确实需要使用
ZipInputStream
ZipOutputStream
复制文件,并在执行过程中进行重命名。如果确实需要,您可以使用自己的缓冲区就地重写文件。该过程确实会导致重新压缩内容,因为标准API无法以压缩形式获取数据


编辑:@Doval指出@megasega在NIO中的使用,new(相对于这个答案)在JavaSE7中。它的性能可能不会很好,三十年前RISC操作系统GUI中的归档文件系统也是如此。

我知道你问过Java,但出于归档目的,我想我会写一篇关于.NET的笔记

是一个用于zip文件的.NET库,允许重命名条目。正如Tom Hawtin的回复所述,目录在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数据都会被写入。

这就成功了。由于它只在cen上工作,因此速度非常快tral目录,而不是文件

//  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();
    }
}
//重新压缩(zipfile,“/main folder”,“/versionXY”);
导入java.io.BufferedOutputStream;
导入java.io.File;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.nio.file.FileSystem;
导入java.nio.file.FileSystems;
导入java.nio.file.FileVisitResult;
导入java.nio.file.Files;
导入java.nio.file.LinkOption;
导入java.nio.file.Path;
导入java.nio.file.path;
导入java.nio.file.SimpleFileVisitor;
导入java.nio.file.attribute.BasicFileAttributes;
受保护的void重新压缩(字符串zipfile、字符串olddir、字符串newdir){
Path-zipFilePath=Path.get(zipfile);
try(FileSystem fs=FileSystems.newFileSystem(zipFilePath,null)){
路径oldpathInsideZipPath=fs.getPath(olddir);
如果(!Files.exists(path.get(newdir)))
Files.createDirectory(path.get(newdir));
if(Files.exists(oldpathInsideZipPath,LinkOption.NOFOLLOW_LINKS)){
walkFileTree(oldpathInsideZipPath,new SimpleFileVisitor()){
@凌驾
公共文件VisitResult visitFile(路径文件,基本文件属性属性属性)
抛出IOException
{
if(file.toString().indexOf(olddir)>-1){
字符串a=file.toString().replaceAll(olddir,newdir);
路径b=fs.getPath(a);
如果(!Files.exists(b.getParent())){
createDirectories(b.getParent());
}
文件.move(文件,b,LinkOption.NOFOLLOW\u链接);
}
返回FileVisitResult.CONTINUE;
}
@凌驾
公共文件VisitResult postVisitDirectory(路径目录,IOE异常)
抛出IOException
{
如果(e==null){
删除(dir);
返回FileVisitResult.CONTINUE;
}否则{
//目录迭代失败
投掷e;
}
}
});
}
fs.close();
}捕获(例外e){
e、 printStackTrace();
}
}

@chieso:问题是关于Java库的。我们不能使用您的代码片段。我知道。我一开始就这样回答。我只想把它放在那里,以防其他人搜索“重命名”和“zip”并且不受Java的限制。中心目录取代了本地目录头,因此可以高效地读取和更新zip文件。在编写此答案时,中使用的不可用,但它在不解压缩和重新压缩文件的情况下更新中心目录。我不需要递归解决方案,但
FileSystems.newFileSystem
plus
Files.move
成功了。唯一需要注意的是,这将生成zip文件的更新副本并删除旧版本,因此对于非常大的归档文件,这可能仍然有点慢,并且您需要足够的磁盘空间来进行复制。不过这仍然要快一个数量级。这允许我在10+GB的存档,只需几秒钟即可创建,耗时数分钟。