Распаковка файлов

79

Я хочу отображать файлы OpenOffice , .odt и .odp на стороне клиента с помощью веб-браузера.

Эти файлы представляют собой заархивированные файлы. Используя Ajax, я могу получить эти файлы с сервера, но это заархивированные файлы. Мне нужно распаковать их с помощью JavaScript , я пробовал использовать inflate.js, http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt , но безуспешно.

Как я могу это сделать?

пользователь69260
источник
7
«безуспешно», пожалуйста, будьте более конкретными, покажите нам код, покажите нам некоторые ошибки ... мы здесь, чтобы помочь, а не угадывать.
OcuS
В основном я просто вызвал функцию inflate - data = zip_inflate (src); Но я думаю, это предназначено для одного файла. Если zip-файлы содержат несколько файлов в структуре каталогов, то каково будет содержимое «данных». Я не знаю, как пользоваться этой библиотекой.
user69260
@Eimantas, что это значит? + Или -
user69260
4
@techfandu: (1) Щелкните свое имя. (2) Щелкните предыдущий вопрос, который вы задали. (3) Примите тот ответ, который помог вам больше всего. (4) Повторяйте, пока на все ваши вопросы не будет принят принятый ответ.
Дэйв Джарвис,
у вас получилось с работой? Я должен сделать то же самое для школьного проекта (поиграть в odp в веб-браузере). Если бы вы могли дать мне несколько советов, это было бы ужасно.
Alexx

Ответы:

61

Я написал распаковщик на Javascript. Оно работает.

Он полагается на программу чтения бинарных файлов Andy GP Na и некоторую логику расширения RFC1951 от notmasteret. . Я добавил класс 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's 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-файл. Существует асинхронный обратный вызов, когда чтение завершается (обычно происходит менее чем за секунду для zip-файлов разумного размера) - в этой демонстрации обратный вызов хранится в локальной переменной doneReading, которая просто вызываетextractEntries , которая просто слепо распаковывает все содержимое предоставленного zip-файл. В реальном приложении вы, вероятно, выберете некоторые записи для извлечения (разрешите пользователю выбрать или выбрать одну или несколько записей программно и т. Д.).

extractEntriesП перебирает все записи и вызовыextract() каждую, передавая обратный вызов. Распаковка записи занимает время, может быть, 1 с или более для каждой записи в zip-файле, что означает, что асинхронность подходит. Обратный вызов extract просто добавляет извлеченный контент в аккордеон jQuery на странице. Если контент является двоичным, он форматируется как таковой (не показан).


Работает, но мне кажется, что полезность несколько ограничена.

Во-первых: это очень медленно. Распаковка 140 КБ файла AppNote.txt из PKWare занимает ~ 4 секунды. То же самое распаковывание может быть выполнено менее чем за 0,5 с в программе .NET. РЕДАКТИРОВАТЬ : Javascript ZipFile распаковывается значительно быстрее, чем сейчас, в IE9 и Chrome. Он по-прежнему медленнее, чем скомпилированная программа, но достаточно быстр для обычного использования браузера.

Для другого: он не выполняет потоковую передачу. По сути, он забирает все содержимое zip-файла в память. В «реальной» среде программирования вы можете читать только метаданные zip-файла (скажем, 64 байта на запись), а затем читать и распаковывать другие данные по желанию. Насколько я знаю, в javascript нет способа сделать такой ввод-вывод в javascript, поэтому единственный вариант - прочитать весь zip-архив в память и выполнить произвольный доступ к нему. Это означает, что для больших zip-файлов он будет предъявлять необоснованные требования к системной памяти. Не такая уж большая проблема для zip-файла меньшего размера.

Также: он не обрабатывает zip-файл «общего случая» - есть множество опций zip, которые я не потрудился реализовать в распаковщике - например, шифрование ZIP, шифрование WinZip, zip64, имена файлов в кодировке UTF-8 и т. Д. на. ( EDIT - теперь он обрабатывает имена файлов в кодировке UTF-8). Однако класс ZipFile обрабатывает основы. Некоторые из этих вещей было бы несложно реализовать. У меня есть класс шифрования AES в Javascript; которые можно интегрировать для поддержки шифрования. Поддержка Zip64, вероятно, бесполезна для большинства пользователей Javascript, поскольку он предназначен для поддержки zip-файлов размером более 4 ГБ - не нужно извлекать их в браузере.

Я также не тестировал случай распаковки двоичного содержимого. Прямо сейчас распаковывает текст. Если у вас есть заархивированный двоичный файл, вам нужно отредактировать класс ZipFile, чтобы он правильно обрабатывался. Я не понял, как это сделать чисто. Теперь он делает и двоичные файлы.


РЕДАКТИРОВАТЬ - Я обновил библиотеку распаковки JS и демонстрацию. Теперь он делает двоичные файлы в дополнение к тексту. Я сделал его более гибким и общим - теперь вы можете указать кодировку, которая будет использоваться при чтении текстовых файлов. Также расширена демонстрация - в ней, помимо прочего, показано распаковывание файла XLSX в браузере.

Так что, хотя я думаю, что это имеет ограниченную полезность и интерес, оно работает. Думаю, это сработает в Node.js.

Cheeso
источник
Выглядит отлично, но я получил это сообщение об ошибке: Этот zip-файл использует UTF8, который не поддерживается ZipFile.js. Какое быстрое решение вы можете порекомендовать?
Джулио Приско,
@Giulio - хорошо, я изменил класс ZipFile для поддержки декодирования имен файлов в кодировке UTF8. Это должно работать сейчас.
Cheeso 07
Потрясающе! Можете ли вы добавить поддержку KMZ (двоичный) и KML (XML) в JSIO.guessFileType?
Брендан Берд,
1
У меня есть старая версия одной из демонстраций в сети , но я пришел сюда за обновлениями. @Cheeso Заинтересованы в обновленных ссылках, когда у вас будет время.
geocodezip 04
1
@DannyBeckett - хорошо, спасибо за напоминание и предложение. Я скоро где-нибудь выложу демо.
Cheeso
26

Я использую zip.js, и он мне кажется весьма полезным. Стоит посмотреть!

Посмотрите , например, демо-версию Unzip .

Дани БИШОП
источник
Я использую zip.js так же, как и вы, но в сафари я получаю, что программа чтения файлов не определена. Пожалуйста, помогите мне работать с сафари.
user969275 01
У меня нет опыта работы с Safari. Обращайтесь к разработчикам zip.js. Внизу страницы проекта есть адрес электронной почты: gildas-lormeau.github.com/zip.js . Возможно, это ошибка, поэтому они будут вам благодарны за уведомление.
Дани епископ 01
Спасибо за ответ, я опубликовал проблему.
user969275 02
У меня есть файлы JSON со строкой JSON в кодировке base64 в формате zip внутри них. Мне нужен этот внутренний объект JSON. InflatorInputStream Java может распаковать его на сервере, поэтому он фактически находится в формате zip. Однако, когда я передаю декодированные данные base64 из atob () в zip.js с помощью BlobReader, я получаю «Ошибка при чтении zip-файла». ошибка. Визуально вывод atob () является двоичным, поэтому BlobReader кажется правильным, все равно попробовал TextReader, он выдает «Формат файла не распознается.». Есть идеи?
enigment
Решил мою проблему одной строкой кода с помощью pako pako.inflate(binaryData, { to: 'string' })
enigment
17

Я нашел jszip весьма полезным. Пока что я использовал только для чтения, но у них также есть возможности создания / редактирования.

По коду это выглядит примерно так

var new_zip = new JSZip();
new_zip.load(file);
new_zip.files["doc.xml"].asText() // this give you the text in the file

Одна вещь, которую я заметил, это то, что кажется, что файл должен быть в формате двоичного потока (читать с помощью .readAsArrayBuffer из FileReader (), иначе я получал ошибки, говоря, что у меня может быть поврежденный zip-файл

Изменить: Примечание из руководства по обновлению с 2.x до 3.0.0 :

Метод load () и конструктор с данными (new JSZip (data)) заменены на loadAsync ().

Спасибо user2677034

АльвароФГ
источник
1
Это мне помогло. Благодарю. :)
deekshith
1
Этот метод был удален в JSZip 3.0, пожалуйста, проверьте руководство по обновлению.
user2677034
1
Спасибо, чувак, это потрясающая библиотека, потому что она очень проста в использовании (по сравнению с предыдущими ответами)!
Максим Георгиевский
5

Если вам нужна поддержка других форматов или просто нужна хорошая производительность, вы можете использовать эту библиотеку WebAssembly.

он обещан на основе, он использует WebWorkers для потоковой передачи, а API на самом деле представляет собой простой модуль ES

MySqlError
источник
3

Я написал «Двоичные инструменты для JavaScript», проект с открытым исходным кодом, который включает возможность распаковывать, распаковывать и распаковывать: https://github.com/codedread/bitjs

Используется в моей программе для чтения комиксов: https://github.com/codedread/kthoom (также с открытым исходным кодом).

HTH!

codedread
источник
2

Пример кода приведен на сайте автора . Вы можете использовать рыбу для перевода текстов (с японского на английский).

Насколько я понимаю по-японски, этот zip-код расширения предназначен для декодирования данных (потоков) ZIP, а не архива ZIP.

OcuS
источник
0

Если кто-то читает изображения или другие двоичные файлы из zip-файла, размещенного на удаленном сервере, вы можете использовать следующий фрагмент для загрузки и создания zip-объекта с помощью библиотеки jszip .

// this function just get the public url of zip file.
let url = await getStorageUrl(path) 
console.log('public url is', url)
//get the zip file to client
axios.get(url, { responseType: 'arraybuffer' }).then((res) => {
  console.log('zip download status ', res.status)
//load contents into jszip and create an object
  jszip.loadAsync(new Blob([res.data], { type: 'application/zip' })).then((zip) => {
    const zipObj = zip
    $.each(zip.files, function (index, zipEntry) {
    console.log('filename', zipEntry.name)
    })
  })

Теперь, используя zipObj, вы можете получить доступ к файлам и создать для них URL-адрес src.

var fname = 'myImage.jpg'
zipObj.file(fname).async('blob').then((blob) => {
var blobUrl = URL.createObjectURL(blob)
ржавый
источник