Как создать java zip архивы с максимальным размером файла
Мне нужно написать алгоритм в Java (для приложения Android), чтобы прочитать папку, содержащую больше папок и каждая из которых содержит изображения и аудиофайлы, поэтому структура такова: mainDir/categorySubfolder/myFile1.jpg
Моя проблема заключается в том, что мне нужно ограничить размер архива до 16 МБ, а во время выполнения создать столько архивов, сколько нужно, чтобы содержать все мои файлы из моего основного mainDir
папка.
Я попробовал несколько примеров из сети, и я прочитал документацию по Java, но не могу понять и собрать все вместе так, как мне нужно. Кто-то делал это раньше или у меня есть ссылка или пример для меня?
Я решил чтение файлов рекурсивным методом, но не могу написать логику для создания zip.
Я открыт для предложений или лучшего рабочего примера.
3 ответа
zip4j - это отличная библиотека, которая может создавать многокомпонентные zip-файлы.
net.lingala.zip4j.core.ZipFile zipFile = new ZipFile("out.zip");
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
zipFile.createZipFileFromFolder("path/to/source/dir", parameters, true, maximum size);
Вы можете найти больше примеров на их веб-сайте.
Я использую приведенный ниже код / класс для разделения и архивирования большого количества / размера файлов. Я проверил этот класс ниже
- количество несжатых файлов: 116
- общий размер (без сжатия): 29,1 ГБ
- Ограничение размера файла ZIP (каждый): 3 ГБ [MAX_ZIP_SIZE]
- общий размер (сжатый): 7,85 ГБ
- номер файла ZIP (разделен как MAX_ZIP_SIZE): 3
Вы должны изменить значение MAX_ZIP_SIZE на 16(МБ)*1024*1024=16777216-22(размер заголовка почтового индекса) =16777194.
В моем коде MAX_ZIP_SIZE установлен на 3 ГБ ( ZIP имеет ограничение 4 ГБ на разные вещи).
окончательный длинный MAX_ZIP_SIZE = 3221225472L; //3 ГБ
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class QDE_ZIP {
public static String createZIP(String directoryPath, String zipFileName, String filesToZip) {
try {
final int BUFFER = 104857600; // 100MB
final long MAX_ZIP_SIZE = 3221225472L; //3 GB
long currentSize = 0;
int zipSplitCount =0;
String files[] = filesToZip.split(",");
if (!directoryPath.endsWith("/")) {
directoryPath = directoryPath + "/";
}
byte fileRAW[] = new byte[BUFFER];
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(directoryPath + zipFileName.toUpperCase()));
ZipEntry zipEntry;
FileInputStream entryFile;
for (String aFile : files) {
zipEntry = new ZipEntry(aFile);
if (currentSize >= MAX_ZIP_SIZE)
{
zipSplitCount ++;
//zipOut.closeEntry();
zipOut.close();
zipOut = new ZipOutputStream(new FileOutputStream(directoryPath + zipFileName.toLowerCase().replace(".zip", "_"+zipSplitCount+".zip").toUpperCase()));
currentSize = 0;
}
zipOut.putNextEntry(zipEntry);
entryFile = new FileInputStream(directoryPath + aFile);
int count;
while ((count = entryFile.read(fileRAW, 0, BUFFER)) != -1) {
zipOut.write(fileRAW, 0, count);
//System.out.println("number of Bytes read = " + count);
}
entryFile.close();
zipOut.closeEntry();
currentSize += zipEntry.getCompressedSize();
}
zipOut.close();
//System.out.println(directory + " -" + zipFileName + " -Number of Files = " + files.length);
} catch (FileNotFoundException e) {
return "FileNotFoundException = " + e.getMessage();
} catch (IOException e) {
return "IOException = " + e.getMessage();
} catch (Exception e) {
return "Exception = " + e.getMessage();
}
return "1";
}
}
Я вернул все сообщения об исключениях в виде строки для работы с ним. это мой собственный случай, связанный с проектом.
Насколько я вижу Как разделить огромный zip-файл на несколько томов? просто предлагает отслеживать размер архива до сих пор, и когда он приближается к какому-то произвольному значению (которое должно быть ниже вашего максимального значения), он решает начать новый файл. Таким образом, для ограничения в 16 МБ вы можете установить значение 10 МБ и начинать новый zip каждый раз, когда это будет достигнуто, но если вы достигнете 9 МБ, а ваш следующий файл уменьшится до 8 МБ, вы получите zip больше, чем ваш лимит.
Код, приведенный в этом посте, похоже, не работает для меня, потому что 1) он получил размер до того, как был создан ZipEntry, поэтому всегда было 0 и 2) он не выписывал zip:-) Если я неправильно понял - дайте мне знать.
Следующее работает для меня. Для простоты я вынул его из оболочки и просто поместил все в main(String args[]). Есть много способов улучшить этот код:-)
import java.util.zip.*;
import java.io.*;
public class ChunkedZipTwo {
static final long MAX_LIMIT=10 * 1000 * 1024; //10MB limit - hopefully this
public static void main(String[] args) throws Exception {
String[] files = {"file1", "file2", "file3"};
int i = 0;
boolean needNewFile = false;
long overallSize = 0;
ZipOutputStream out = getOutputStream(i);
byte[] buffer = new byte[1024];
for (String thisFileName: files) {
if (overallSize > MAX_LIMIT) {
out.close();
i++;
out = getOutputStream(i);
overallSize=0;
}
FileInputStream in = new FileInputStream(thisFileName);
ZipEntry ze = new ZipEntry(thisFileName);
out.putNextEntry(ze);
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
out.closeEntry();
in.close();
overallSize+=ze.getCompressedSize();
}
out.close();
}
public static ZipOutputStream getOutputStream(int i) throws IOException {
ZipOutputStream out = new ZipOutputStream(new FileOutputStream("bigfile" + i +".zip"));
out.setLevel(Deflater.DEFAULT_COMPRESSION);
return out;
}
}