Ответ 1
Я написал unzipper в Javascript. Оно работает.
Он полагается на Энди Г.П. Na для чтения бинарных файлов и некоторые RFC1951 раздувают логику от notmasteryet. Я добавил класс ZipFile.
рабочий пример:
http://cheeso.members.winisp.net/Unzip-Example.htm (мертвая ссылка)
Источник:
http://cheeso.members.winisp.net/srcview.aspx?dir=js-unzip (мертвая ссылка)
NB: ссылки мертвы; Скоро найду нового хозяина.
В качестве источника используется демонстрационная страница ZipFile.htm и 3 разных сценария, один для класса zipfile, один для класса inflate и один для класса чтения двоичных файлов. Демо также зависит от jQuery и jQuery UI. Если вы просто загрузите файл js-zip.zip, там будет весь необходимый источник.
Вот что выглядит код приложения в Javascript:
// In my demo, this gets attached to a click event.
// it instantiates a ZipFile, and provides a callback that is
// invoked when the zip is read. This can take a few seconds on a
// large zip file, so it asynchronous.
var readFile = function(){
$("#status").html("<br/>");
var url= $("#urlToLoad").val();
var doneReading = function(zip){
extractEntries(zip);
};
var zipFile = new ZipFile(url, doneReading);
};
// this function extracts the entries from an instantiated zip
function extractEntries(zip){
$('#report').accordion('destroy');
// clear
$("#report").html('');
var extractCb = function(id) {
// this callback is invoked with the entry name, and entry text
// in my demo, the text is just injected into an accordion panel.
return (function(entryName, entryText){
var content = entryText.replace(new RegExp( "\\n", "g" ), "<br/>");
$("#"+id).html(content);
$("#status").append("extract cb, entry(" + entryName + ") id(" + id + ")<br/>");
$('#report').accordion('destroy');
$('#report').accordion({collapsible:true, active:false});
});
}
// for each entry in the zip, extract it.
for (var i=0; i<zip.entries.length; i++) {
var entry = zip.entries[i];
var entryInfo = "<h4><a>" + entry.name + "</a></h4>\n<div>";
// contrive an id for the entry, make it unique
var randomId = "id-"+ Math.floor((Math.random() * 1000000000));
entryInfo += "<span class='inputDiv'><h4>Content:</h4><span id='" + randomId +
"'></span></span></div>\n";
// insert the info for one entry as the last child within the report div
$("#report").append(entryInfo);
// extract asynchronously
entry.extract(extractCb(randomId));
}
}
Демонстрация работает в два этапа: readFile
fn запускается щелчком и создает объект ZipFile, который читает zip файл. Там асинхронный обратный вызов для того, когда чтение завершается (как правило, происходит менее чем за секунду для разумных размеров zips) - в этой демонстрации обратный вызов сохраняется в локальной переменной doneReading, которая просто вызывает extractEntries
, что
просто слепо распаковывает все содержимое предоставленного zip файла. В реальном приложении вы, вероятно, выберете некоторые из извлекаемых записей (разрешите пользователю выбирать или выбирать одну или несколько записей программно и т.д.).
extractEntries
fn выполняет итерацию по всем записям и вызывает на каждом из них extract()
, передавая обратный вызов. Декомпрессия записи занимает время, возможно, 1 с или больше для каждой записи в zip файле, что означает, что асинхронность является подходящей. Обратный вызов extract просто добавляет извлеченный контент в аккордеон jQuery на странице. Если содержимое двоично, то оно форматируется как таковое (не показано).
Это работает, но я думаю, что утилита несколько ограничена.
С одной стороны: это очень медленно. Занимает ~ 4 секунды, чтобы разархивировать 140k файл AppNote.txt из PKWare. Такое же uncompress можно сделать менее чем за 0,5 с в .NET-программе. EDIT: Javascript ZipFile распаковывается значительно быстрее, чем это сейчас, в IE9 и в Chrome. Он по-прежнему медленнее, чем скомпилированная программа, но для обычного использования браузера он достаточно быстрый.
Для другого: он не выполняет потоковую передачу. Это в основном завалы во всем содержимом zipfile в память. В "реальной" среде программирования вы можете читать только метаданные zip файла (скажем, 64 байта на запись), а затем читать и распаковывать другие данные по желанию. Невозможно сделать IO, как в javascript, насколько я знаю, поэтому единственный вариант - прочитать весь zip в памяти и сделать произвольный доступ в нем. Это означает, что для больших zip файлов будут предъявляться необоснованные требования к системной памяти. Не так много для небольшого zip файла.
Кроме того: он не обрабатывает zip файл "общий регистр" - есть много опций zip, которые я не удосужился реализовать в unzipper - как шифрование ZIP, шифрование WinZip, zip64, UTF- 8 закодированных имен файлов, и т.д. ( EDIT - теперь он обрабатывает имена файлов с кодировкой UTF-8). Однако класс ZipFile обрабатывает основы. Некоторые из этих вещей не будут трудно реализовать. У меня класс шифрования AES в Javascript; которые могут быть интегрированы для поддержки шифрования. Поддержка Zip64, вероятно, будет бесполезной для большинства пользователей Javascript, поскольку она предназначена для поддержки > 4gb zipfiles - не нужно извлекать их в браузере.
Я также не тестировал случай распаковки двоичного содержимого. Прямо сейчас он распаковывает текст. Если у вас есть заархивированный двоичный файл, вам нужно будет отредактировать класс ZipFile для правильной обработки. Я не понял, как это сделать. Теперь он делает двоичные файлы.
EDIT. Я обновил библиотеку JS и демо-версию. Теперь он содержит двоичные файлы, в дополнение к тексту. Я сделал его более устойчивым и более общим - теперь вы можете указать кодировку, используемую при чтении текстовых файлов. Кроме того, демонстрационная версия расширена - она показывает, помимо прочего, файл XLSX в браузере.
Итак, хотя я думаю, что он имеет ограниченную полезность и интерес, он работает. Я предполагаю, что это сработает в Node.js.