Сжатие Java 7zip слишком велико - PullRequest
0 голосов
/ 07 января 2019

У меня есть программа на Java, которая ищет папку с датой вчерашнего дня, сжимает ее в 7zip-файл и в конце удаляет. Теперь я заметил, что созданные моей программой файлы архива 7zip слишком велики. Когда я использую программу типа 7-Zip File Manager для сжатия моих файлов, она создает архив размером 5 КБ, в то время как моя программа создает архив размером 737 КБ для тех же файлов (размер которых составляет 873 КБ). Теперь я боюсь, что моя программа не сжимает его в 7zip-файл, а делает обычный zip-файл. Есть ли способ изменить что-то в моем коде так, чтобы он генерировал меньший 7zip-файл, как это сделал бы 7-Zip File Manager?

package SevenZip;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;

import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;

public class SevenZipUtils {

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

        String sourceFolder = "C:/Users/Ferid/Documents/Dates/";
        String outputZipFile = "/Users/Ferid/Documents/Dates";
        int sleepTime = 0;
        compress(sleepTime, outputZipFile, sourceFolder);
    }

    public static boolean deleteDirectory(File directory, int sleepTime) throws InterruptedException {
        if (directory.exists()) {
            File[] files = directory.listFiles();
            if (null != files) {
                for (int i = 0; i < files.length; i++) {
                    if (files[i].isDirectory()) {
                        deleteDirectory(files[i], sleepTime);
                        System.out.println("Folder deleted: " + files[i]);
                    } else {
                        files[i].delete();
                        System.out.println("File deleted: " + files[i]);
                    }
                }
            }
        }
        TimeUnit.SECONDS.sleep(sleepTime);
        return (directory.delete());
    }

    public static void compress(int sleepTime, String outputZipFile, String sourceFolder)
            throws IOException, InterruptedException {

        // finds folder of yesterdays date
        final Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1); // date of yesterday
        String timeStamp = new SimpleDateFormat("yyyyMMdd").format(cal.getTime()); // format the date
        System.out.println("Yesterday was " + timeStamp);

        if (sourceFolder.endsWith("/")) { // add yesterday folder to sourcefolder path
            sourceFolder = sourceFolder + timeStamp;
        } else {
            sourceFolder = sourceFolder + "/" + timeStamp;
        }

        if (outputZipFile.endsWith("/")) { // add yesterday folder name to outputZipFile path
            outputZipFile = outputZipFile + " " + timeStamp + ".7z";
        } else {
            outputZipFile = outputZipFile + "/" + timeStamp + ".7z";
        }

        File file = new File(sourceFolder);

        if (file.exists()) {
            try (SevenZOutputFile out = new SevenZOutputFile(new File(outputZipFile))) {
                addToArchiveCompression(out, file, ".");
                System.out.println("Files sucessfully compressed");

                deleteDirectory(new File(sourceFolder), sleepTime);
            }
        } else {
            System.out.println("Folder does not exist");
        }
    }

    private static void addToArchiveCompression(SevenZOutputFile out, File file, String dir) throws IOException {
        String name = dir + File.separator + file.getName();
        if (file.isFile()) {
            SevenZArchiveEntry entry = out.createArchiveEntry(file, name);
            out.putArchiveEntry(entry);

            FileInputStream in = new FileInputStream(file);
            byte[] b = new byte[1024];
            int count = 0;
            while ((count = in.read(b)) > 0) {
                out.write(b, 0, count);
            }
            out.closeArchiveEntry();
            in.close();
            System.out.println("File added: " + file.getName());
        } else if (file.isDirectory()) {
            File[] children = file.listFiles();
            if (children != null) {
                for (File child : children) {
                    addToArchiveCompression(out, child, name);
                }
            }
            System.out.println("Directory added: " + file.getName());
        } else {
            System.out.println(file.getName() + " is not supported");
        }
    }
}

Я использую библиотеку Apache Commons Compress

РЕДАКТИРОВАТЬ: Вот ссылка , где у меня есть код сжатия Apache Commons от.

Ответы [ 3 ]

0 голосов
/ 14 января 2019

У меня недостаточно представителей, чтобы больше комментировать, поэтому вот мои мысли:

  • Я не вижу, где вы устанавливаете степень сжатия, поэтому может быть, что SevenZOutputFile не использует (или очень низкое) сжатие. Как сказал @CristiFati, разница в сжатии странная, особенно для текстовых файлов
  • Как отмечает @ df778899, нет поддержки сплошного сжатия, благодаря чему достигается наилучшая степень сжатия, поэтому вы не сможете сделать это так же, как командная строка 7z

Тем не менее, если zip действительно не вариант, ваш последний вариант может быть вызвать соответствующую командную строку непосредственно в вашей программе .

Если использование чистого 7z не является обязательным, другой вариант может заключаться в использовании формата, подобного «tgz», для эмуляции сплошного сжатия: сначала сжимайте все файлы в несжатый файл (например, в формате tar или в zip-файле без сжатия) , затем сжатие этого файла в режиме zip с помощью стандартного алгоритма Java Deflate. Конечно, это будет жизнеспособно, только если этот формат распознается другими процессами, использующими его.

0 голосов
/ 15 января 2019

Используйте 7-Zip архиватор файлов , вместо этого он легко сжимает 832 KB файл в 26.0 KB:

  1. Получите его Баночка и SDK .
  2. Выберите LZMA Compression .java связанные файлы.
  3. Добавить Run аргументы к свойствам проекта: e "D:\\2017ASP.pdf" "D:\\2017ASP.7z", e обозначает encode, "input path" "output path".
  4. Запустите проект [LzmaAlone.java].

Результаты

Case1 (.pdf файл): От 33,969 KB до 24,645 KB.

Case2 (файл .docx): От 832 KB до 26.0 KB.

0 голосов
/ 10 января 2019

Commons Compress запускает новый блок в файле контейнера для каждой записи архива. Обратите внимание на счетчик блоков здесь:

block-per-file

Не совсем тот ответ, на который вы надеялись, но в документах говорится, что он не поддерживает «сплошное сжатие» - запись нескольких файлов в один блок. См. Пункт 5 в документах здесь .

Беглый осмотр обнаружил несколько других библиотек Java, которые поддерживают сжатие LZMA, но я не смог найти такую, которая могла бы сделать это в формате файла родительского контейнера для 7-Zip. Возможно, кто-то еще знает об альтернативе ...

Звучит как обычный формат файла zip (например, через ZipOutputStream ), это не вариант?

...