Розпакування файлів


79

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

Ці файли є архівами. Використовуючи Ajax, я можу отримати ці файли з сервера, але це файли в архіві. Я повинен розпакувати їх за допомогою JavaScript , я спробував використовувати inflate.js, http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt , але безуспішно.

Як я можу це зробити?


7
"без успіху", будь ласка, будьте конкретнішими, покажіть нам якийсь код, покажіть нам деякі помилки ... ми тут, щоб допомогти, а не вгадати.
— OcuS

В основному я щойно викликав функцію роздування - data = zip_inflate (src); Але я думаю, що це призначено для одного файлу. Якщо zip-файли містять кілька файлів у структурі каталогів, то яким буде вміст "даних". Я не знаю, як користуватися цією бібліотекою.
— user69260

@Eimantas що це означає? + Або -
— user69260

4
@techfandu: (1) Клацніть на своє ім'я. (2) Клацніть на попереднє запитання, яке ви задавали. (3) Прийміть відповідь, яка вам найбільше допомогла. (4) Повторюйте, поки на всі ваші запитання не буде прийнято відповіді.
— Dave Jarvis

Ви досягли успіху в роботі? Я повинен зробити те ж саме для проекту в школі (відтворити odp у веб-браузері) .. Якби ви могли дати мені деякі вказівки, це було б неймовірно.
— Alexx,

Відповіді:


61

Я написав розпаковку в Javascript. Це працює.

Він покладається на зчитувач двійкових файлів Andy GP 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, один для класу надування та інший для класу зчитування двійкових файлів. Демо-версія також залежить від 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));
    }
}

Демонстрація працює в кілька кроків: readFilefn запускається клацанням і створює екземпляр об’єкта ZipFile, який зчитує zip-файл. Існує асинхронний зворотний виклик, коли зчитування завершується (зазвичай це відбувається менш ніж за секунду для стиснутих ZIP-кодів розумного розміру) - у цій демонстрації зворотний виклик утримується в локальній змінній doneReading, яка просто викликає extractEntries, яка просто наосліп розпаковує весь вміст наданого zip-файл. У реальному додатку ви, мабуть, вибрали б деякі записи, які потрібно витягти (дозволити користувачеві вибрати, або вибрати один або декілька записів програмно тощо).

У extractEntriesFn перебирає всі записи, і виклики extract()на кожному з них, проходячи зворотний виклик. Декомпресія запису вимагає часу, може бути 1s або більше для кожного запису в zip-файлі, що означає, що асинхронність є доречною. Витяг зворотного виклику просто додає витягнутий вміст до акордеону jQuery на сторінці. Якщо вміст є двійковим, то він відформатовується як такий (не показано).


Це працює, але я думаю, що корисність дещо обмежена.

Одне: це дуже повільно. Розпакування файлу 140k AppNote.txt із PKWare займає ~ 4 секунди. Те саме розпакування можна зробити менш ніж за .5 с у програмі .NET. EDIT : Javascript ZipFile розпаковується значно швидше, ніж зараз, в IE9 та Chrome. Це все ще повільніше, ніж скомпільована програма, але вона досить швидка для звичайного використання браузера.

Для іншого: він не робить потокового передавання. По суті, це весь вміст zip-файлу в пам'ять. У "реальному" середовищі програмування ви можете читати лише метадані ZIP-файлу (скажімо, 64 байти на запис), а потім читати та розпаковувати інші дані за бажанням. Наскільки мені відомо, неможливо зробити подібне введення-виведення в javascript, тому єдиний варіант - прочитати весь zip-файл у пам’яті та зробити в ньому довільний доступ. Це означає, що це спричинить необґрунтовані вимоги до системної пам'яті для великих ZIP-файлів. Не стільки проблема для меншого zip-файлу.

Також: він не обробляє zip-файл "загального випадку" - існує безліч варіантів zip, які я не потрудився застосувати в розпаковці - наприклад, шифрування ZIP, шифрування WinZip, zip64, кодовані назви файлів UTF-8 тощо. на. ( EDIT - тепер обробляє кодовані імена файлів UTF-8). Однак клас ZipFile обробляє основи. Деякі з цих речей не складно реалізувати. У мене є клас шифрування AES у Javascript; які можуть бути інтегровані для підтримки шифрування. Підтримка Zip64, мабуть, була б марною для більшості користувачів Javascript, оскільки вона призначена для підтримки> 4gb zip-файлів - не потрібно витягувати їх у браузері.

Я також не перевіряв справу на розпакування двійкового вмісту. Зараз він розпаковує текст. Якщо у вас є заархівований двійковий файл, вам потрібно буде відредагувати клас ZipFile, щоб правильно його обробляти. Я не зрозумів, як це робити чисто. Зараз він також робить двійкові файли.


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

Отже, хоча я думаю, що це обмежено корисно та цікаво, це працює. Я думаю, це працювало б у Node.js.


Це виглядає чудово, але я отримав таке повідомлення про помилку: Цей zip-файл використовує UTF8, який не підтримується ZipFile.js. Будь-який швидкий обхідний шлях, який ви можете порадити?
— Джуліо Пріско

@Giulio - добре, я змінив клас ZipFile для підтримки декодування імен файлів, закодованих UTF8. Це має просто працювати зараз.
— Cheeso

Чудово! Чи можете ви додати підтримку KMZ (двійковий) та KML (XML) до JSIO.guessFileType?
— Brendan Byrd

1
У мене є стара версія однієї з демонстраційних версій в Інтернеті , але я прийшов сюди шукати оновлення. @Cheeso Буде зацікавлений в оновлених посиланнях, коли у вас буде час.
— геокодезіп 04.03.13

1
@DannyBeckett - добре, дякую за нагадування та пропозицію. Незабаром я десь викладу демо.
— Cheeso

26

Я використовую zip.js, і це видається дуже корисним. Варто подивитися!

Наприклад, перевірте демонстрацію розпакування .


я використовую zip.js те саме, що і ви, але в сафарі я отримую програму читання файлів не визначено. pls допоможе мені працювати з сафарі.
— user969275 01.03.13

У мене немає досвіду роботи з Safari. Вам слід звернутися до розробників zip.js. Внизу сторінки проекту є електронна адреса: gildas-lormeau.github.com/zip.js . Можливо, це помилка, тому вони подякують вам за повідомлення.
— Дани Єпископ

Дякуємо за відповідь, я опублікував проблему.
— user969275 02.03.13

У мене є файли JSON з кодованим рядком JSON base64 у форматі zip. Мені потрібен внутрішній об'єкт JSON. InflatorInputStream Java може розпакувати його на сервері, тому насправді він знаходиться у форматі zip. Однак, коли я передаю декодовані дані base64 з atob () до zip.js за допомогою BlobReader, я отримую "Помилка під час читання zip-файлу". помилка. Візуально вихід з atob () є двійковим, тому BlobReader здається правильним, спробував TextReader у будь-якому випадку, він дає "Формат файлу не розпізнається." Будь-які ідеї?
— загадка

Зіграло свою проблему в одному рядку коду з 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 () та конструктор з даними (новий JSZip (дані)) замінено loadAsync ().

Дякую користувачеві 2677034


1
Це мені допомогло. Дякую. :)
— deekshith

1
Цей метод було вилучено в JSZip 3.0, перегляньте посібник з оновлення.
— user2677034

1
Дякую, чудова бібліотека, адже вона надзвичайно проста у використанні (порівняно з попередніми відповідями)!
— Максим Георгієвський

5

Якщо вам потрібна підтримка інших форматів або просто вам потрібна хороша продуктивність, ви можете скористатися цією бібліотекою WebAssembly

це обіцяно, він використовує WebWorkers для створення потоків, а API насправді є простим модулем ES


3

Я написав "Бінарні інструменти для JavaScript", проект з відкритим кодом, що включає можливість розпаковувати, розпаковувати та розпаковувати: https://github.com/codedread/bitjs

Використовується в моєму читачі коміксів: https://github.com/codedread/kthoom (також з відкритим кодом).

HTH!


2

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

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



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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.