在 Java 中重命名 Zip 文件中的文件/文件夹?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/847892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Renaming a File/Folder inside a Zip File in Java?
提问by Simon07
I have a zip file containing a folder structure like
我有一个包含文件夹结构的 zip 文件,例如
- main-folder/
- subFolder1/
- subFolder2/
- subFolder3/
- file3.1
- file3.2
- 主文件夹/
- 子文件夹1/
- 子文件夹2/
- 子文件夹3/
- 文件3.1
- 文件3.2
I would like to rename folder main-folderto let's say versionXYinside that very zip file using Java.
我想重命名文件夹main-folder,让我们说versionXY在使用 Java 的那个非常 zip 文件中。
Is there a simpler way than extracting the whole zip file and recreating a new one using the new folder names?
有没有比提取整个 zip 文件并使用新文件夹名称重新创建一个新文件更简单的方法?
回答by Tom Hawtin - tackline
Zip is an archive format, so mutating generally involves rewriting the file.
Zip 是一种存档格式,因此变异通常涉及重写文件。
Some particular features of zip also get in the way (zip is full of "features"). As well as the central directory at the end of the archive, each component file is preceded by its file name. Zip doesn't have a concept of directories - file names are just strings that happen to include "/" characters (and substrings such as "../".
zip 的一些特殊功能也有碍观瞻(zip 充满了“功能”)。除了存档末尾的中央目录外,每个组件文件前面都有其文件名。Zip 没有目录的概念——文件名只是碰巧包含“/”字符(以及诸如“../”之类的子字符串)的字符串。
So, you really need to copy the file using ZipInputStreamand ZipOutputStream, renaming as you go. If you really wanted to you could rewrite the file in place doing your own buffering. The process does cause the contents to be recompressed as the standard API has no means of obtaining the data in compressed form.
因此,您确实需要使用ZipInputStreamand复制文件,并随时ZipOutputStream重命名。如果你真的想要你可以重写文件做你自己的缓冲。该过程确实会导致内容被重新压缩,因为标准 API 无法以压缩形式获取数据。
回答by Cheeso
I know you asked about Java but just for archival purposes I thought I would contribute a note about .NET.
我知道你问过 Java,但只是为了存档目的,我想我会贡献一篇关于 .NET 的笔记。
DotNetZipis a .NET library for zip files that allows renaming of entries. As Tom Hawtin's reply states, directories are not first-class entities in the zip file metadata, and as a result, no zip libraries that I know of expose a "rename directory" verb. But some libraries allow you to rename all the entries that have names that indicate a particular directory, which gives you the result you want.
DotNetZip是一个用于 zip 文件的 .NET 库,允许重命名条目。正如 Tom Hawtin 的回复所述,目录不是 zip 文件元数据中的一流实体,因此,据我所知,没有任何 zip 库公开“重命名目录”动词。但是有些库允许您重命名所有具有指示特定目录的名称的条目,这会为您提供所需的结果。
In DotNetZip, it would look like this:
在 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
}
}
You can also add or remove entries, inside the using clause.
您还可以在 using 子句中添加或删除条目。
If you save to the same file, then DotNetZip rewrites only the changed metadata - the entry headers and the central directory records for renamed entries, which saves time with large archives. If you save to a new file or stream, then all of the zip data gets written.
如果您保存到同一个文件,则 DotNetZip 仅重写更改的元数据 - 条目标题和重命名条目的中央目录记录,这可以节省大型档案的时间。如果您保存到新文件或流,则所有 zip 数据都会被写入。
回答by Valentin Rocher
I think you'll be able to find help for this task using the Commons Compress, especially ZipArchiveEntry
我认为您将能够使用Commons Compress找到此任务的帮助,尤其是ZipArchiveEntry
回答by megasega
This is doing the trick. Blazing fast since it works only on the central directory and not the files.
这是在做伎俩。速度很快,因为它仅适用于中央目录而不适用于文件。
// 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();
}
}

