Java, распаковать папку с немецкими символами в именах файлов - PullRequest
1 голос
/ 28 марта 2019

Я пытаюсь распаковать папку с немецкими символами, например, Aufhänge.Я знаю, что в Java 7 по умолчанию используется utf-8, и я думаю, что «ä» - один из символов utf-8.Вот мой фрагмент кода

public static void main(String[] args) throws IOException {
    ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(ZIP_PATH), StandardCharsets.UTF_8);
    ZipEntry zipEntry;
    while ((zipEntry = zipInputStream.getNextEntry()) != null) {
        System.out.println(zipEntry.getName());
    }
}

Это ошибка, которую я получаю: java.lang.IllegalArgumentException: MALFORMED

Он работает с Charset.forName ("Cp437"), но это не так.не работает с StandardCharsets.UTF_8

1 Ответ

0 голосов
/ 02 мая 2019

Вы не упоминаете ни свою операционную систему, ни то, как вы создали zip-файл, но мне все равно удалось воссоздать вашу проблему, используя 7-Zip в Windows 10:

  • Создайте простой текстовый файл с некоторым тривиальным содержимым (например, только с тремя символами «abc»).
  • Сохраните файл как D: \ Temp \ Aufhänge.txt .Обратите внимание на умлаут в имени файла.
  • Найдите этот файл в проводнике Windows.
  • Выберите файл и щелкните правой кнопкой мыши.В контекстном меню выберите 7-Zip> Добавить в «Aufhänge.zip» , чтобы создать Aufhänge.zip .

Затем в NetBeans выполните следующую командукод для распаковки только что созданного файла:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class GermanZip {

    static String ZIP_PATH = "D:\\Temp\\Aufhänge.zip";

    public static void main(String[] args) throws FileNotFoundException, IOException {

        ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(ZIP_PATH), Charset.forName("UTF-8"));
        ZipEntry zipEntry;
        while ((zipEntry = zipInputStream.getNextEntry()) != null) {
            System.out.println(zipEntry.getName());
        }
    }

}

Как вы указали, при выполнении этого оператора код выдает java.lang.IllegalArgumentException: MALFORMED: zipEntry = zipInputStream.getNextEntry()) != null.

Проблема возникает из-за того, что по умолчанию 7-Zip кодирует имена файлов в zip-файле с использованием Cp437, как отмечено в в этом комментарии от 7-Zip :

По умолчанию используется кодировка OEM (DOS) .Это для совместимости со старым программным обеспечением zip.

Вот почему распаковка работает при использовании Charset.forName("Cp437") вместо Charset.forName("UTF-8").

Если вы хотите распаковать с помощью Charset.forName("UTF-8"), тогда выдолжны заставить 7-Zip кодировать имена файлов внутри zip в UTF-8.Для этого укажите параметр cu при запуске 7-Zip , как указано в связанном комментарии:

  • В проводнике Windows выберите файл и щелкните правой кнопкой мыши.нажмите кнопку.
  • В контекстном меню выберите 7-Zip> Добавить в архив ... ".
  • В диалоговом окне Добавить в архив укажите у.е. в поле Параметры :

    AddToArchive

  • Храня молнииимена файлов в формате UTF-8, затем вы можете заменить Charset.forName("Cp437") на Charset.forName("UTF-8") в своем коде, и при разархивировании не возникнет никаких исключений.

Этот ответ относится только к Windows 10и 7-Zip, но общий принцип должен применяться в любой среде: если вы задаете кодировку UTF-8 для вашего ZipInputStream, убедитесь, что имена файлов в zip-файле действительно кодируются с использованием UTF-8.открыв zip-файл в бинарном редакторе и выполнив поиск по названию zip-файлов.


Обновление на основе комментария / вопроса ОП ниже:

  • К сожалению, Спецификация формата файла * .ZIP *1093* в настоящее время не обеспечивает способ хранениякодировка, используемая для заархивированных имен файлов, за исключением одного исключения, как описано в «ПРИЛОЖЕНИИ D - Language Encoding (EFS)»:

    D.2 Если бит 11 общего назначения не установлен, имя файла иКомментарий ДОЛЖЕН соответствовать оригинальной кодировке символов ZIP. Если установлен бит 11 общего назначения, имя файла и комментарий ДОЛЖНЫ поддерживать стандарт Unicode версии 4.1.0 или выше с использованием формы кодировки символов, определенной в спецификации хранения UTF-8. Стандарт Unicode публикуетсяКонсорциум Unicode (www.unicode.org).Ожидается, что данные в кодировке UTF-8, хранящиеся в ZIP-файлах, не будут содержать метки порядка байтов (BOM).

  • Таким образом, в вашем коде для каждого сжатого файла сначала проверьте,установлен бит 11 универсального бита .Если это так, то вы можете быть уверены, что имя этого заархивированного файла закодировано с помощью UTF-8 .В противном случае кодировка будет той, которая использовалась при создании архива.Это Cp437 по умолчанию в Windows, но если вы работаете в Windows и обрабатываете zip-файл, созданный в Linux, я не думаю, что есть простой способ определить используемую кодировку.

  • К сожалению ZipEntry не предоставляет метод для доступа к полю универсальный битовый флаг ZIP-файла, поэтому вам нужно будет обработать ZIP-файл вуровень байтов, чтобы сделать это.
  • Чтобы добавить дополнительную сложность, «кодировка» в этом контексте относится к кодировке, используемой для каждого сжатого файла, а не для самого файла ZIP. Одно сжатое имя файла может быть закодировано в UTF-8 , другое сжатое имя файла может быть добавлено с использованием Cp437 и т. Д.
...