Я уже давно борюсь с этой проблемой. Кажется, что все вопросы здесь, в SO или интернете, работают только над «неглубокими» структурами с одним почтовым индексом внутри другого. Однако у меня есть zip-архив, структура которого более или менее примерно такая:
input.zip/
--1.zip/
--folder/
----2.zip/
------3.zip/
--------test/
----------some-other-folder/
----------archive.gz/
------------filte-to-parse
----------file-to-parse3.txt
------file-to-parse.txt
--4.zip/
------folder/
и т. Д., мой код должен обрабатывать N-уровень zips при сохранении оригинальных zip-архивов. , gzips, папки и структура файлов. Использование временных файлов запрещено из-за отсутствия привилегий (это то, что я не хочу менять).
Это мой код, который я написал до сих пор, однако ZipOutputStream
, кажется, работает только с одним (top) уровень - в случае каталогов с одинаковыми именами файлов / каталогов он выдает Exception in thread "main" java.util.zip.ZipException: duplicate entry: folder/
. Он также пропускает пустые каталоги (что не ожидается). Чего я хочу добиться, так это как-то переместить мой ZipOutputStream
на «более низкий» уровень и выполнять операции с каждым из почтовых индексов. Может быть, есть лучший подход для решения этой проблемы, любая помощь будет оценена. Мне нужно выполнить определенное извлечение / модификацию текста позже, однако я пока не запускаю его, пока чтение / запись всей структуры не будет работать должным образом. Заранее благодарю за любую помощь!
//constructor
private final File zipFile;
ArchiveResolver(String fileToHandle) {
this.zipFile = new File(Objects.requireNonNull(getClass().getClassLoader().getResource(fileToHandle)).getFile());
}
void resolveInputFile() throws Exception {
FileInputStream fileInputStream = new FileInputStream(this.zipFile);
FileOutputStream fileOutputStream = new FileOutputStream("out.zip");
ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);
ZipInputStream zipInputStream = new ZipInputStream(fileInputStream);
zip(zipInputStream, zipOutputStream);
zipInputStream.close();
zipOutputStream.close();
}
// this one doesn't preserve internal structure(empty folders), but can work on each file
private void zip(ZipInputStream zipInputStream, ZipOutputStream zipOutputStream) throws IOException {
ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) {
System.out.println(entry.getName());
byte[] buffer = new byte[1024];
int length;
if (entry.getName().endsWith(".zip")) {
// wrapping outer zip streams to inner streams making actual entries a new source
ZipInputStream innerZipInputStream = new ZipInputStream(zipInputStream);
ZipOutputStream innerZipOutputStream = new ZipOutputStream(zipOutputStream);
ZipEntry zipEntry = new ZipEntry(entry.getName());
// add new zip entry here to outer zipOutputStream: i.e. data.zip
zipOutputStream.putNextEntry(zipEntry);
// now treat this data.zip as parent and call recursively zipFolder on it
zip(innerZipInputStream, innerZipOutputStream);
// Finish internal stream work when innerZipOutput is done
innerZipOutputStream.finish();
// Close entry
zipOutputStream.closeEntry();
} else if (entry.isDirectory()) {
// putting new zip entry into output stream and adding extra '/' to make
// sure zipOutputStream will treat it as folder
ZipEntry zipEntry = new ZipEntry(entry.getName() + "/");
// this only should preserve internal structure
zipOutputStream.putNextEntry(zipEntry);
// reading everything from zipInputStream
while ((length = zipInputStream.read(buffer)) > 0) {
// sending it straight to zipOutputStream
zipOutputStream.write(buffer, 0, length);
}
zipOutputStream.closeEntry();
// This else will include checking if file is respectively:
// .gz file <- then open it, read from file inside, modify and save it
// .txt file <- also read, modify and preserve
} else {
// create new entry on top of this
ZipEntry zipEntry = new ZipEntry(entry.getName());
zipOutputStream.putNextEntry(zipEntry);
while ((length = zipInputStream.read(buffer)) > 0) {
zipOutputStream.write(buffer, 0, length);
}
zipOutputStream.closeEntry();
}
}
}
// This one preserves internal structure (empty folders and so)
// BUT! no work on each file is possible it just preserves everything as it is
private void zipWhole(ZipInputStream zipInputStream, ZipOutputStream zipOutputStream) throws IOException {
ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) {
System.out.println(entry.getName());
byte[] buffer = new byte[1024];
int length;
zipOutputStream.putNextEntry(new ZipEntry(entry.getName()));
while ((length = zipInputStream.read(buffer)) > 0) {
zipOutputStream.write(buffer, 0, length);
}
zipOutputStream.closeEntry();
}
}
РЕДАКТИРОВАТЬ:
Обновил мой код до последней версии, все еще нечем гордиться, но сделал некоторые изменения, однако все еще не работает ... ЯЯ добавил сюда два очень важных комментария о (на мой взгляд) коде, который не работает. Итак, я протестировал два подхода - первый получает ZipInputStream
из zipFile
с помощью getInputStream(ZipEntry e);
- выдает Exception in thread "main" java.util.zip.ZipException: no current ZIP entry
, когда я пытаюсь поместить некоторые записи в ZipOutputStream
. Второй подход фокусируется на "оборачивании" ZipInputStream
друг в друга -> это приводит к пустым ZipInputStream
s без записей, и приложение просто просматривает файлы, перечисляет их (только верхний уровень zips ...) и завершает безсохранив что-нибудь в файл out.zip
.
РЕДАКТИРОВАТЬ 2:
С небольшими предложениями от людей в комментариях я решил переписать свой код с упором на close, finish и closeEntryв соответствующих местах (надеюсь, я сделал это лучше сейчас). Итак, сейчас я кое-чего достиг - код перебирает каждую запись и сохраняет ее в файле out.zip с соответствующей упаковкой zip внутри. Тем не менее пропускает пустые папки, но не знаю почему (я проверил некоторые вопросы по стеку и в Интернете, кажется, все в порядке). В любом случае, спасибо за помощь, я постараюсь решить эту проблему и буду постоянно обновлять.