Java Zip + русские буквы в названиях файлов


Баг №4244499

Этот баг был зарегистрирован еще в 1999г.
Проблема была не только с русскими файлами, а например с французскими (как в примере).
Корни довольно глубокие и существовали серьезные (надеюсь) причины, по которым эту ошибку долгое время не исправляли. В итоге, много-много лет в Java нельзя было сделать простыми штатными средствами zip-архив, который бы содержал файлы с именами не на латинице.

К сожалению, жизнь такова, что все это время некоторых java-программистов заставляли делать такие zip-архивы. Приходилось использовать например apache-вский commons-compress.

Использовать очень просто. Алгоритм буквально в два шага:
Шаг 1. Загружаем jar-ик (ссылка) или просто добавляем в pom.xml зависимость (если maven) :

    
        ....
        
            org.apache.commons
            commons-compress
            1.3
        
    

Шаг 2. Используем:

import java.io.File;
import java.io.FileInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import static org.apache.commons.compress.utils.IOUtils.copy;
/*
 * ТОЛЬКО В ОЗНАКОМИТЕЛЬНЫХ ЦЕЛЯХ! 
 * Пример очень небрежный, в реальных задачах код нужно причесать!
 * Author: Vit 
 */
public class Sample {

    public static void main(String[] args) throws Exception {
        File srcDir = new File("c:/temp/dir");
        // список файлов
        File[] files = srcDir.listFiles();
        File zipFile = new File(srcDir, srcDir.getName() + ".zip");
        // архив
        ZipArchiveOutputStream zaos = new ZipArchiveOutputStream(zipFile);
        for (File itemFile : files) {
            ZipArchiveEntry entry = new ZipArchiveEntry(itemFile.getName());
            zaos.putArchiveEntry(entry);
            FileInputStream fis = new FileInputStream(itemFile);
            try {
               // копируем потоки
                copy(fis, zaos);
            } finally {
                fis.close();
            }
            zaos.closeArchiveEntry();
        }
        zaos.close();
    }
}

Счастливый конец.

В текущей версии JDK 7 этого бага уже нет.
Во-первых в семерке в ZIP API добавили новый конструктор, в котором можно явно указывать кодировку:
ZipOutputStream(OutputStream out,Charset charset)

Во-вторых, по-умолчанию используется стандартная UTF-8 кодировка.
Таким образом, дополнительных библиотек использовать не нужно, можно сразу делать zip-архив:

 /* 
 * ТОЛЬКО В ОЗНАКОМИТЕЛЬНЫХ ЦЕЛЯХ! 
 * Пример очень небрежный, в реальных задачах код нужно причесать!
 * Author: Vit 
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class Sample {
    public static void main(String[] args) throws Exception {
        File srcDir = new File("c:/temp/dir");
        File[] files = srcDir.listFiles();
        File zipFile = new File(srcDir, srcDir.getName() + "_j7.zip");
        FileOutputStream fos = new FileOutputStream(zipFile);
        
        try (ZipOutputStream zos = new ZipOutputStream(fos)) {
            for (File itemFile : files) {
                ZipEntry entry = new ZipEntry(itemFile.getName());
                zos.putNextEntry(entry);
                
                try (FileInputStream fis = new FileInputStream(itemFile)) {
                    byte[] buff = new byte[8192];
                    int length = -1;
                    while (-1 != (length = fis.read(buff))) {
                        zos.write(buff, 0, length);
                    }
                }
                zos.closeEntry();
            }
        }
    }
 }
Любое использование либо копирование материалов или подборки материалов сайта, элементов дизайна и оформления допускается лишь с разрешения правообладателя и только со ссылкой на источник: programador.ru

Телеграм канал: @prgrmdr
Почта для связи: vit [at] programmisty.com