2017-01-09 13 views
1

Я пытаюсь создать архив 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 

Но при открытии созданного архива есть две папки внутри:

Ä? 
ą 

Первый пуст, и текстовый файл так же, как и в каталоге «±».

ответ

1

Кажется 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, вы получите в обеих записях.

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 

Если вы не можете заставить путь открыт почтовый файл (если почтовый файл отправляется пользователи вместо одного из ваших серверов) или использовать только символы ASCII в ваших папках, использование другой библиотеки выглядит как единственное решение.