Добавить имена файлов, отличных от ASCII, в zip-архив в Java

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

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

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();
        }
    }
}

truezip с UTF-8 работал у меня на windows 7 и mac os x 10.6.x. Это все еще не работает в Linux?

Anton Kuzmin 23.11.2009 20:37

В JDK до v7 была давняя ошибка - 9 лет существования - которая препятствовала правильной обработке имен файлов с именами, которые нельзя было закодировать с помощью IBM CP437. bugs.sun.com/bugdatabase/view_bug.do?bug%5Fid=4244499 Очевидно, это было исправлено в JDK7. blogs.oracle.com/xuemingshen/entry/non_utf_8_encoding_in Таким образом, одним из решений является использование JDK7 и новых конструкторов для ZipInputStream, ZipOutputStream и ZipFile.

Cheeso 15.06.2012 20:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
19
2
23 231
7

Ответы 7

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

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

Micke 20.09.2008 03:36

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

Извини!

Согласно спецификации PKWare, есть положение о том, что имя файла, о котором идет речь, закодировано с помощью UTF-8. Кодировка UTF-8 в zip-файлах пока широко не поддерживается (== еще не поддерживается в проводнике Windows). Когда бит UTF-8 не установлен в заголовке записи zip, в спецификации zip указано, что имя файла должно быть закодировано в IBM437. Но вы правы, некоторые приложения (WinRar) просто кодируют системную кодовую страницу по умолчанию. Не уверен, что проводник Windows делает это. Несоблюдение правильной кодировки при чтении zip-архива может фактически привести к недоступности файлов.

Cheeso 19.05.2009 19:20

Беглый взгляд на TrueZIP руководство - они рекомендуют формат JAR:

It uses UTF-8 for file name encoding and comments - unlike ZIP, which only uses IBM437.

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

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

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

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

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

Обновлено: при ошибке кто-то предлагает использовать ZipOutputStream из Apache Ant в качестве временного решения. Эта реализация позволяет специфицировать кодировку.

«Похоже, исторически обозначается как IBM CP437» - это немного нечетко. В спецификации PKWare сказано, что в именах файлов для кодирования используется IBM437, точка. В 2007 году PKWare добавила стандартный способ использования UTF-8. Есть инструменты, которые не используют ни того, ни другого, но это выходит за рамки спецификации!

Cheeso 28.03.2009 11:22

Спасибо за разъяснения, я изменил ответ.

Mnementh 30.03.2009 15:33

вы написали: «если этот бит установлен, все записи в имени файла должны быть закодированы в UTF-8». Это не так. Использование UTF-8 или IBM437 для каждой записи, а не для архива. Соответствующий спецификации zip-файл может содержать некоторые записи с именами в кодировке UTF-8, а другие - в IBM437.

Cheeso 19.05.2009 19:17

Чтобы добавить путаницы, немецкая установка Windows распакует архивы с cp850. веселые времена.

user3850 01.06.2010 20:19

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

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

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

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

Почему анонимно проголосовали против? Вам не нравится точная информация?

Cheeso 26.07.2009 17:09

Я до сих пор не понимаю, почему этот ответ отклоняется. Это точная и верная информация Все еще. Если у кого-то есть возражения или кто-то считает, что информация в этом ответе неверна, сообщите об этом.

Cheeso 01.06.2010 20:32

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

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

Вот запись в блоге о Чуде, опубликованная в июне 2012 года: blogs.oracle.com/xuemingshen/entry/non_utf_8_encoding_in

Cheeso 15.06.2012 20:50

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

Вызова setEncoding ("UTF-8") в вашем потоке должно быть достаточно.

Другие вопросы по теме