使用包含特殊字符的目录创建zip

时间:2017-01-09 21:50:38

标签: java zip

我正在尝试创建一个包含一些目录的zip存档。一些目录的名称中包含波兰语字母,如:ą,ę,ł等。一切都很好看,但对于名称中包含特殊字母的任何目录,在zip文件中创建另一个目录。以下代码有什么问题:

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException; 
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class Main {

  public static void main(String[] args) throws URISyntaxException, IOException {
    Map<String, String> env = new HashMap<>();
    env.put("create", "true");
    URI fileUri = new File("zipfs.zip").toPath().toUri();
    URI zipUri = new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null);

    try (FileSystem zipfs = FileSystems.newFileSystem(zipUri, env)) {

        Path directory = zipfs.getPath("ą");
        Files.createDirectory(directory);
        Path pathInZipfile = directory.resolve("someFile.txt");
        Path source = Paths.get("source.txt");

        Files.copy(source, pathInZipfile, StandardCopyOption.REPLACE_EXISTING);
    }

    FileSystem zipFs = FileSystems.newFileSystem(zipUri, Collections.emptyMap());

    Path root = zipFs.getPath("/");

    Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
            System.out.println(path);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            System.out.println(dir);
            return super.preVisitDirectory(dir, attrs);
        }
    });
  }
}

此计划的输出符合预期:

/
/ą/
/ą/someFile.txt

但是当你打开创建的zip文件时,里面有两个目录:

Ä?  
ą

第一个是空的,文本文件应该在'±'目录中。

1 个答案:

答案 0 :(得分:2)

似乎ZipFileSystem没有为文件夹设置语言编码标志(EFS)。这个标志基本上说“这条路径使用UTF-8”。

让我们看看zipdetails(跳过没有兴趣的行):

0072 CENTRAL HEADER #1     02014B50
007A General Purpose Flag  0000                       // <= no EFS flag
00A0 Filename              'ą/'

00AC CENTRAL HEADER #2     02014B50
00B4 General Purpose Flag  0800
     [Bits 1-2]            0 'Normal Compression'
     [Bit 11]              1 'Language Encoding'      // <= EFS flag
00DA Filename              'ą/someFile.txt'

否则,ą/在UTF-8中正确编码。

没有此标志,由程序读取/解压缩zip文件以选择编码(通常是系统默认值)。 unzip在这里效果不佳:

$ unzip -t zipfs.zip 
Archive:  zipfs.zip
    testing: -à/                      OK
    testing: ą/someFile.txt          OK
No errors detected in compressed data of zipfs.zip.

注意,如果您使用-UU停用unicode支持,则两个条目都会获得

7z在这里效果更好(但仅因为我的系统默认编码是UTF-8):

$ 7z l zipfs.zip
...
   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2017-01-10 22:51:14 D....            0            0  ą
2017-01-10 22:51:15 .....            0            2  ą/someFile.txt
------------------- ----- ------------ ------------  ------------------------
2017-01-10 22:51:15                  0            2  1 files, 1 folders

如果您无法强制打开zip文件的方式(例如,如果将zip文件发送给用户而不是您的某个服务器)或仅在文件夹中使用ASCII字符,则使用不同的库看起来像唯一的解决方案。