Добавить не-ASCII имена файлов в zip в Java - PullRequest
19 голосов
/ 20 сентября 2008

Каков наилучший способ добавления не-ASCII имен файлов в zip-файл с использованием Java таким образом, чтобы файлы могли быть правильно читать в Windows и Linux?

Вот одна попытка, адаптированная из https://truezip.dev.java.net/tutorial-6.html#Example,, которая работает в Windows Vista, но не работает в Ubuntu Hardy. В Hardy имя файла отображается как abc-ЖДФ.txt в file-roller.

import java.io.IOException;
import java.io.PrintStream;

import de.schlichtherle.io.File;
import de.schlichtherle.io.FileOutputStream;

public class Main {

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

        try {
            PrintStream ps = new PrintStream(new FileOutputStream(
                    "outer.zip/abc-åäö.txt"));
            try {
                ps.println("The characters åäö works here though.");
            } finally {
                ps.close();
            }
        } finally {
            File.umount();
        }
    }
}

В отличие от java.util.zip, truezip позволяет указать кодировку zip-файла. Вот еще один пример, на этот раз явно указывающий кодировку. Ни IBM437, ни UTF-8, ни ISO-8859-1 не работают в Linux. IBM437 работает в Windows.

import java.io.IOException;

import de.schlichtherle.io.FileOutputStream;
import de.schlichtherle.util.zip.ZipEntry;
import de.schlichtherle.util.zip.ZipOutputStream;

public class Main {

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

        for (String encoding : new String[] { "IBM437", "UTF-8", "ISO-8859-1" }) {
            ZipOutputStream zipOutput = new ZipOutputStream(
                    new FileOutputStream(encoding + "-example.zip"), encoding);
            ZipEntry entry = new ZipEntry("abc-åäö.txt");
            zipOutput.putNextEntry(entry);
            zipOutput.closeEntry();
            zipOutput.close();
        }
    }
}

Ответы [ 7 ]

10 голосов
/ 14 октября 2008

Кодировка записей файлов в ZIP изначально указана как кодовая страница IBM 437. Многие символы, используемые на других языках, невозможно использовать таким образом.

Спецификация PKWARE относится к проблеме и добавляет немного. Но это более позднее дополнение (с 2007 года спасибо Cheeso за разъяснения, см. Комментарии). Если этот бит установлен, запись имени файла должна быть закодирована в UTF-8. Это расширение описано в «ПРИЛОЖЕНИИ D - Языковая кодировка (EFS)», которое находится в конце связанного документа.

Для Java это известная ошибка, из-за которой возникают проблемы с не-ASCII-символами. См. ошибка # 4244499 и большое количество связанных ошибок.

Мой коллега использовал в качестве обходного пути URL-кодирование имен файлов перед сохранением их в ZIP и расшифровкой после прочтения. Если вы контролируете и хранение, и чтение, это может быть обходным путем.

РЕДАКТИРОВАТЬ: В баге кто-то предлагает использовать ZipOutputStream от Apache Ant в качестве обходного пути. Эта реализация позволяет задавать кодировку.

8 голосов
/ 28 июля 2010

Чудеса действительно случаются, и Sun / Oracle действительно исправили долгоживущую ошибку / rfe:

Теперь можно настроить кодировки файлов при создании файла / потока zip ( требует Java 7 ).

8 голосов
/ 04 января 2009

В Zip-файлах, согласно спецификации, принадлежащей PKWare, кодировка имен файлов и комментариев к файлам - IBM437. В 2007 году PKWare расширил спецификации, чтобы также разрешить UTF-8. Это ничего не говорит о кодировке файлов, содержащихся в zip. Только кодировка имен файлов.

Я думаю, что все инструменты и библиотеки (Java и не Java) поддерживают IBM437 (который является расширенным набором ASCII), и меньшее количество инструментов и библиотек поддерживают UTF-8. Некоторые инструменты и библиотеки поддерживают другие кодовые страницы. Например, если вы заархивировали что-то с помощью WinRar на компьютере, работающем в Шанхае, вы получите кодовую страницу Big5. Это не "разрешено" спецификацией почтового индекса, но это происходит в любом случае.

Библиотека DotNetZip для .NET поддерживает Unicode, но, конечно, это не поможет вам, если вы используете Java!

Используя встроенную поддержку Java для ZIP, вы всегда получите IBM437. Если вам нужен архив с чем-то отличным от IBM437, используйте стороннюю библиотеку или создайте JAR.

7 голосов
/ 17 декабря 2010

Вы все еще можете использовать реализацию Apache Commons потока zip: http://commons.apache.org/compress/apidocs/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.html#setEncoding%28java.lang.String%29

Достаточно вызвать setEncoding ("UTF-8") в вашем потоке.

3 голосов
/ 20 сентября 2008

Из краткого руководства TrueZIP - они рекомендуют формат JAR:

Используется UTF-8 для кодирования имени файла. и комментарии - в отличие от ZIP, который только использует IBM437.

Это, вероятно, означает, что API использует для своей реализации пакет java.util.zip ; эта документация утверждает, что она все еще использует формат ZIP с 1996 . Поддержка Unicode не была добавлена ​​в спецификацию формата PKWARE .ZIP до 2006 года.

0 голосов
/ 20 сентября 2008

Имена файлов, не относящихся к ASCII, не надежны во всех реализациях ZIP и их лучше избегать. Не предусмотрено сохранение настроек кодировки в ZIP-файлах; клиенты склонны угадывать «текущую системную кодовую страницу», что вряд ли будет тем, что вам нужно. Многие комбинации клиента и кодовой страницы могут привести к недоступности файлов.

Извините!

0 голосов
/ 20 сентября 2008

Это действительно не удалось или это просто проблема со шрифтом? (например, шрифт с разными глифами для этих кодов) Я видел похожие проблемы в Windows, где рендеринг «ломался», потому что шрифт не поддерживал кодировку, но на самом деле данные были целыми и правильными.

...