Dateien entpacken


79

Ich möchte OpenOffice- Dateien, .odt und .odp auf der Clientseite mit einem Webbrowser anzeigen .

Diese Dateien sind komprimierte Dateien. Mit Ajax kann ich diese Dateien vom Server abrufen, aber es handelt sich um komprimierte Dateien. Ich muss sie mit JavaScript entpacken . Ich habe versucht, inflate.js, http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt , zu verwenden, aber ohne Erfolg.

Wie kann ich das machen?


7
"kein Erfolg" bitte genauer sein, zeigen Sie uns einen Code, zeigen Sie uns einige Fehler ... wir sind hier, um zu helfen, nicht um zu raten.
OcuS

Grundsätzlich habe ich gerade Inflate-Funktion genannt - data = zip_inflate (src); Aber ich denke, das ist für einzelne Dateien gedacht. Wenn eine Zip-Datei mehrere Dateien in einer Verzeichnisstruktur enthält, wie lautet dann der Inhalt von "Daten"? Ich weiß nicht, wie ich diese Bibliothek benutzen soll.
Benutzer69260

@Eimantas was bedeutet das? + Oder -
user69260

4
@techfandu: (1) Klicken Sie auf Ihren Namen. (2) Klicken Sie auf eine vorherige Frage, die Sie gestellt haben. (3) Akzeptiere die Antwort, die dir am meisten geholfen hat. (4) Wiederholen Sie diesen Vorgang, bis alle Ihre Fragen eine akzeptierte Antwort haben.
Dave Jarvis

Haben Sie mit der Arbeit Erfolg gehabt? Ich muss das Gleiche für ein Projekt in der Schule tun (Odp in einem Webbrowser spielen). Wenn Sie mir einige Hinweise geben könnten, wäre es großartig.
Alexx

Antworten:


61

Ich habe einen Entpacker in Javascript geschrieben. Es klappt.

Es basiert auf dem Binärdateireader von Andy GP Na und einer RFC1951-Aufblaslogik von notmasteryet . Ich habe die ZipFile-Klasse hinzugefügt.

Arbeitsbeispiel:
http://cheeso.members.winisp.net/Unzip-Example.htm (toter Link)

Die Quelle:
http://cheeso.members.winisp.net/srcview.aspx?dir=js-unzip (toter Link)

NB : Die Links sind tot. Ich werde bald einen neuen Gastgeber finden.

In der Quelle sind eine ZipFile.htm-Demonstrationsseite und drei verschiedene Skripte enthalten, eines für die Zipfile-Klasse, eines für die Inflate-Klasse und eines für eine Binärdateireaderklasse. Die Demo hängt auch von jQuery und der jQuery-Benutzeroberfläche ab. Wenn Sie nur die Datei js-zip.zip herunterladen, ist die gesamte erforderliche Quelle vorhanden.


So sieht der Anwendungscode in Javascript aus:

// 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));
    }
}

Die Demo funktioniert in wenigen Schritten: Das readFilefn wird durch einen Klick ausgelöst und instanziiert ein ZipFile-Objekt, das die Zip-Datei liest. Es gibt einen asynchronen Rückruf, wenn der Lesevorgang abgeschlossen ist (normalerweise in weniger als einer Sekunde bei Zips mit angemessener Größe). In dieser Demo wird der Rückruf in der lokalen Variablen doneReading gehalten, die einfach aufruft extractEntriesund den gesamten Inhalt des bereitgestellten einfach blind entpackt zip-Datei. In einer echten App würden Sie wahrscheinlich einige der zu extrahierenden Einträge auswählen (dem Benutzer erlauben, einen oder mehrere Einträge programmgesteuert auszuwählen usw.).

Das extractEntriesfn durchläuft alle Einträge und ruft extract()jeden auf, wobei ein Rückruf weitergeleitet wird. Die Dekomprimierung eines Eintrags benötigt Zeit, möglicherweise 1s oder mehr für jeden Eintrag in der Zip-Datei, was bedeutet, dass Asynchronität angemessen ist. Der Rückruf zum Extrahieren fügt den extrahierten Inhalt einfach einem jQuery-Akkordeon auf der Seite hinzu. Wenn der Inhalt binär ist, wird er als solcher formatiert (nicht gezeigt).


Es funktioniert, aber ich denke, dass das Dienstprogramm etwas eingeschränkt ist.

Zum einen: Es ist sehr langsam. Das Entpacken der 140k-Datei AppNote.txt aus PKWare dauert ca. 4 Sekunden. Die gleiche Dekomprimierung kann in einem .NET-Programm in weniger als 0,5 Sekunden durchgeführt werden. EDIT : Die Javascript ZipFile auspackt deutlich schneller als das jetzt, in IE9 und in Chrome. Es ist immer noch langsamer als ein kompiliertes Programm, aber für die normale Verwendung des Browsers ist es schnell genug.

Zum anderen: Es wird kein Streaming durchgeführt. Es schlürft im Grunde den gesamten Inhalt der Zip-Datei in den Speicher. In einer "echten" Programmierumgebung können Sie nur die Metadaten einer Zip-Datei einlesen (z. B. 64 Byte pro Eintrag) und dann die anderen Daten wie gewünscht lesen und dekomprimieren. Soweit ich weiß, gibt es keine Möglichkeit, solche E / A-Vorgänge in Javascript durchzuführen. Daher besteht die einzige Möglichkeit darin, die gesamte Zip-Datei in den Speicher einzulesen und wahlfrei darauf zuzugreifen. Dies bedeutet, dass für große Zip-Dateien unangemessene Anforderungen an den Systemspeicher gestellt werden. Für eine kleinere Zip-Datei kein Problem.

Außerdem: Die Zip-Datei "Allgemein" wird nicht behandelt. Es gibt viele Zip-Optionen, die ich nicht im Unzipper implementiert habe - wie ZIP-Verschlüsselung, WinZip-Verschlüsselung, zip64, UTF-8-codierte Dateinamen usw. auf. ( BEARBEITEN - es verarbeitet jetzt UTF-8-codierte Dateinamen). Die ZipFile-Klasse übernimmt jedoch die Grundlagen. Einige dieser Dinge wären nicht schwer zu implementieren. Ich habe eine AES-Verschlüsselungsklasse in Javascript. das könnte integriert werden, um die Verschlüsselung zu unterstützen. Die Unterstützung von Zip64 wäre für die meisten Benutzer von Javascript wahrscheinlich nutzlos, da es beabsichtigt, Zip-Dateien mit> 4 GB zu unterstützen - Sie müssen diese nicht in einem Browser extrahieren.

Ich habe den Fall auch nicht zum Entpacken von binären Inhalten getestet. Im Moment wird der Text entpackt. Wenn Sie eine komprimierte Binärdatei haben, müssen Sie die ZipFile-Klasse bearbeiten, um sie ordnungsgemäß zu verarbeiten. Ich habe nicht herausgefunden, wie ich das sauber machen soll. Es macht jetzt auch Binärdateien.


BEARBEITEN - Ich habe die JS-Entpackungsbibliothek und die Demo aktualisiert. Zusätzlich zum Text werden jetzt Binärdateien ausgeführt. Ich habe es widerstandsfähiger und allgemeiner gemacht - Sie können jetzt die Codierung angeben, die beim Lesen von Textdateien verwendet werden soll. Auch die Demo wird erweitert - sie zeigt unter anderem das Entpacken einer XLSX-Datei im Browser.

Obwohl ich denke, dass es von begrenztem Nutzen und Interesse ist, funktioniert es. Ich denke, es würde in Node.js funktionieren.


Das sieht gut aus, aber ich habe folgende Fehlermeldung erhalten: Diese Zip-Datei verwendet UTF8, das von ZipFile.js nicht unterstützt wird. Gibt es eine schnelle Problemumgehung, die Sie empfehlen können?
Giulio Prisco

@ Giulio - ok, ich habe die ZipFile-Klasse geändert, um die Dekodierung von UTF8-codierten Dateinamen zu unterstützen. Es sollte jetzt einfach funktionieren.
Cheeso

Genial! Können Sie JSIO.guessFileType Unterstützung für KMZ (Binär) und KML (XML) hinzufügen?
Brendan Byrd

1
Ich habe eine alte Version einer der Demos online , bin aber hierher gekommen, um nach Updates zu suchen. @Cheeso Würde mich für aktualisierte Links interessieren, wenn Sie Zeit haben.
Geocodezip

1
@DannyBeckett - ok, danke für die Erinnerung und den Vorschlag. Ich werde die Demo bald irgendwo veröffentlichen.
Cheeso

26

Ich benutze zip.js und es scheint sehr nützlich zu sein. Es ist einen Blick wert!

Überprüfen Sie beispielsweise die Demo zum Entpacken .


Ich benutze die zip.js genauso wie Sie, aber in Safari bekomme ich den Filereader nicht definiert. Bitte helfen Sie mir, mit Safari zu arbeiten.
user969275

Ich habe keine Erfahrung mit Safari. Sie sollten sich an die Entwickler von zip.js wenden. Am Ende der Projektseite befindet sich eine E-Mail-Adresse: gildas-lormeau.github.com/zip.js . Vielleicht ist es ein Fehler, also werden sie Ihnen für die Benachrichtigung danken.
Dani Bischof

Vielen Dank für die Antwort, ich habe ein Problem gepostet.
user969275

Ich habe JSON-Dateien mit einer Base64-codierten JSON-Zeichenfolge im Zip-Format. Ich brauche das innere JSON-Objekt. Javas InflatorInputStream kann es auf dem Server entpacken, sodass es tatsächlich im Zip-Format vorliegt. Wenn ich jedoch die dekodierten base64-Daten von atob () mit dem BlobReader an zip.js übergebe, wird "Fehler beim Lesen der Zip-Datei" angezeigt. Error. Visuell ist die Ausgabe von atob () binär, daher scheint der BlobReader richtig zu sein. Versuchen Sie es trotzdem mit dem TextReader. Es wird angezeigt, dass das Dateiformat nicht erkannt wird. Irgendwelche Ideen?
Enigment

Ich habe mein Problem in einer Codezeile mit pako pako.inflate(binaryData, { to: 'string' })
enigment

17

Ich fand jszip sehr nützlich. Ich habe bisher nur zum Lesen verwendet, aber sie haben auch Funktionen zum Erstellen / Bearbeiten.

Code weise sieht es ungefähr so ​​aus

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

Eine Sache, die mir aufgefallen ist, ist, dass die Datei anscheinend im Binär-Stream-Format vorliegen muss (Lesen mit dem .readAsArrayBuffer von FileReader (). Andernfalls wurde die Fehlermeldung angezeigt, dass möglicherweise eine beschädigte Zip-Datei vorhanden ist

Bearbeiten: Hinweis aus dem Upgrade-Handbuch für 2.x auf 3.0.0 :

Die load () -Methode und der Konstruktor mit Daten (neues JSZip (Daten)) wurden durch loadAsync () ersetzt.

Vielen Dank user2677034


1
Das hat mir geholfen. Vielen Dank. :)
Deekshith

1
Diese Methode wurde in JSZip 3.0 entfernt. Weitere Informationen finden Sie in der Upgrade-Anleitung.
user2677034

1
Danke Mann, es ist erstaunlich lib, weil es super einfach zu bedienen ist (im Vergleich zu früheren Antworten)!
Maxim Georgievskiy

5

Wenn Sie auch andere Formate unterstützen müssen oder nur eine gute Leistung benötigen, können Sie diese WebAssembly-Bibliothek verwenden

Es basiert auf Versprechungen, verwendet WebWorkers für das Threading und die API ist eigentlich ein einfaches ES-Modul





0

Wenn jemand Bilder oder andere Binärdateien aus einer auf einem Remote-Server gehosteten Zip-Datei liest, können Sie das folgende Snippet verwenden, um Zip-Objekte mithilfe der jszip- Bibliothek herunterzuladen und zu erstellen .

// 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)
    })
  })

Jetzt können Sie mit zipObj auf die Dateien zugreifen und eine src-URL dafür erstellen.

var fname = 'myImage.jpg'
zipObj.file(fname).async('blob').then((blob) => {
var blobUrl = URL.createObjectURL(blob)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.