IO::Compress::Zip читается из файлового дескриптора в буфер
Я пытаюсь создать zip-файл на лету и отправить его в браузер. я использую IO::Compress::Zip
с IO::String
для этого, но это не работает, как я ожидал от документации.
Сначала мой код:
my $zipped_file;
foreach (@{$par{directory}}) {
my $input = IO::String->new($_->[0]);
zip $input => \$zipped_file, Append => 1, BinModeIn => 1|0; # Tried both for BinModeIn
}
return $zipped_file;
$par{directory}
является arrayref со следующей структурой:
[
['DATA', 'FILENAME'], ['DATA', 'FILENAME'], ...
]
Данные в $par{directory}
строка такая:
<?xml version="1.0" encoding="UTF-8"?>
<derivatives>
<derivative ag="111520420" vhash="d6712f201155a9afb64dc5a5ba369c99">
//Some data
</derivative>
</derivatives>
Все, что я получаю, когда я пытаюсь загрузить файл в виде.zip-архива с одним пустым файлом. Любые намеки на то, что я делаю здесь не так?
Заранее спасибо.
РЕДАКТИРОВАТЬ: Это странно. Я сейчас попробовал это:
use strict;
use warnings;
use IO::Compress::Zip 'zip';
my $xml1 = <<END_XML;
<?xml version="1.0" encoding="UTF-8"?>
<derivatives>
<derivative ag="111520420" vhash="d6712f201155a9afb64dc5a5ba369c99">
//Some data
</derivative>
</derivatives>
END_XML
my $xml2 = <<END_XML;
<?xml version="1.0" encoding="UTF-8"?>
<derivatives2>
<derivative2 ag="111520420" vhash="d6712f201155a9afb64dc5a5ba369c99">
//Some data
</derivative2>
</derivatives2>
END_XML
my $files = [[$xml1, 'xml1'], [$xml2, 'xml2']];
my $zipped_file;
foreach (@$files) {
open my $input, '<', \$_->[0];
zip $input => \$zipped_file, Append => 1, BinModeIn => 1;
}
open my $fh, '>:raw', 'zip.zip';
print $fh $zipped_file;
close $fh;
Архив до сих пор пуст.
2 ответа
Опция " Добавить" для zip не делает то, что вы ожидаете. Он не обновляет существующий zip-файл. Он создает новый и добавляет его в файл / буфер, который вы предоставляете. В вашем случае вы получите серию контейнеров на молнии один за другим.
Вот способ добиться того, чего вы хотите, с помощью Archive::Zip::SimpleZip - это всего лишь оболочка для IO::Compress::Zip, написанная для обработки этого типа сценария использования.
use Archive::Zip::SimpleZip ;
my $zipped_file;
my $zip = new Archive::Zip::SimpleZip \$zipped_file ;
foreach (@{$par{directory}}) {
$zip->addString($_->[0], Name => $_->[1]);
}
$zip->close();
return $zipped_file;
Я думаю, что проблема, скорее всего, связана с тем, что вы делаете с $zipped_file
после того, как вы его создали.
Программа ниже работает для меня. Я записал заархивированную строку в двоичный файл, и разархивирование ее с помощью отдельной утилиты доставляет оригинальный XML.
Я бы предпочел отказаться IO::String
и использовать встроенный open my $input, '<', \$_->[0]
вместо этого, но, кажется, работает в любом случае.
use strict;
use warnings;
use IO::Compress::Zip 'zip';
use IO::String;
my $xml = <<END_XML;
<?xml version="1.0" encoding="UTF-8"?>
<derivatives>
<derivative ag="111520420" vhash="d6712f201155a9afb64dc5a5ba369c99">
//Some data
</derivative>
</derivatives>
END_XML
my $zipped_file;
my $input = IO::String->new($xml);
zip $input => \$zipped_file, Append => 0, BinModeIn => 1;
open my $fh, '>:raw', 'zip.zip';
print $fh $zipped_file;
close $fh;
Обновить
Кстати, кажется, что вообще нет необходимости открывать поток ввода-вывода для входных данных: вы можете просто передать ссылку на скаляр, содержащий данные. Таким образом, выше становится просто
my $zipped_file;
zip \$xml => \$zipped_file, Append => 0, BinModeIn => 1;
open my $fh, '>:raw', 'zip.zip';
print $fh $zipped_file;
close $fh;