Escribí un descomprimidor en Javascript. Funciona.
Se basa en el lector de archivos binarios de Andy GP Na y en alguna lógica de inflado RFC1951 de notmasteryet . Agregué la clase ZipFile.
ejemplo de trabajo:
http://cheeso.members.winisp.net/Unzip-Example.htm (enlace muerto)
La fuente:
http://cheeso.members.winisp.net/srcview.aspx?dir=js-unzip (enlace muerto)
NB : los enlaces están muertos; Pronto encontraré un nuevo anfitrión.
En la fuente se incluye una página de demostración ZipFile.htm y 3 scripts distintos, uno para la clase zipfile, uno para la clase inflar y otro para una clase de lector de archivos binarios. La demostración también depende de jQuery y jQuery UI. Si acaba de descargar el archivo js-zip.zip, todas las fuentes necesarias están allí.
Así es como se ve el código de la aplicación en Javascript:
var readFile = function(){
$("#status").html("<br/>");
var url= $("#urlToLoad").val();
var doneReading = function(zip){
extractEntries(zip);
};
var zipFile = new ZipFile(url, doneReading);
};
function extractEntries(zip){
$('#report').accordion('destroy');
$("#report").html('');
var extractCb = function(id) {
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 (var i=0; i<zip.entries.length; i++) {
var entry = zip.entries[i];
var entryInfo = "<h4><a>" + entry.name + "</a></h4>\n<div>";
var randomId = "id-"+ Math.floor((Math.random() * 1000000000));
entryInfo += "<span class='inputDiv'><h4>Content:</h4><span id='" + randomId +
"'></span></span></div>\n";
$("#report").append(entryInfo);
entry.extract(extractCb(randomId));
}
}
La demostración funciona en un par de pasos: el readFile
fn se activa con un clic y crea una instancia de un objeto ZipFile, que lee el archivo zip. Hay una devolución de llamada asincrónica para cuando se completa la lectura (generalmente ocurre en menos de un segundo para cremalleras de tamaño razonable); en esta demostración, la devolución de llamada se mantiene en la variable local doneReading, que simplemente llama extractEntries
, que simplemente descomprime ciegamente todo el contenido de la archivo zip. En una aplicación real, probablemente elegiría algunas de las entradas para extraer (permitir que el usuario seleccione o elija una o más entradas mediante programación, etc.).
El extractEntries
fn itera sobre todas las entradas y llama extract()
a cada una, pasando una devolución de llamada. La descompresión de una entrada lleva tiempo, tal vez 1 so más por cada entrada en el archivo zip, lo que significa que la asincronía es apropiada. La devolución de llamada de extracción simplemente agrega el contenido extraído a un acordeón jQuery en la página. Si el contenido es binario, se formatea como tal (no se muestra).
Funciona, pero creo que la utilidad es algo limitada.
Por un lado: es muy lento. Tarda ~ 4 segundos en descomprimir el archivo 140k AppNote.txt de PKWare. La misma descompresión se puede realizar en menos de .5 segundos en un programa .NET. EDITAR : El Javascript ZipFile se descomprime considerablemente más rápido que esto ahora, en IE9 y en Chrome. Sigue siendo más lento que un programa compilado, pero es bastante rápido para el uso normal del navegador.
Por otro: no hace streaming. Básicamente, absorbe todo el contenido del archivo zip en la memoria. En un entorno de programación "real", podría leer solo los metadatos de un archivo zip (por ejemplo, 64 bytes por entrada) y luego leer y descomprimir los demás datos como desee. No hay forma de hacer IO así en javascript, hasta donde yo sé, por lo tanto, la única opción es leer todo el zip en la memoria y hacer acceso aleatorio en él. Esto significa que impondrá demandas irrazonables a la memoria del sistema para archivos zip grandes. No es tanto un problema para un archivo zip más pequeño.
Además: no maneja el archivo zip "caso general" - hay muchas opciones zip que no me molesté en implementar en el descomprimidor - como cifrado ZIP, cifrado WinZip, zip64, nombres de archivo codificados en UTF-8, etc. en. ( EDITAR : ahora maneja nombres de archivo codificados en UTF-8). Sin embargo, la clase ZipFile maneja lo básico. Algunas de estas cosas no serían difíciles de implementar. Tengo una clase de cifrado AES en Javascript; que podría integrarse para admitir el cifrado. La compatibilidad con Zip64 probablemente sería inútil para la mayoría de los usuarios de Javascript, ya que está destinada a admitir archivos zip> 4gb, no es necesario extraerlos en un navegador.
Tampoco probé el caso para descomprimir contenido binario. Ahora mismo descomprime el texto. Si tiene un archivo binario comprimido, necesitará editar la clase ZipFile para manejarlo correctamente. No descubrí cómo hacerlo limpiamente. Ahora también hace archivos binarios.
EDITAR - Actualicé la biblioteca de descomprimir JS y la demostración. Ahora hace archivos binarios, además de texto. Lo he hecho más resistente y más general: ahora puede especificar la codificación que se usará al leer archivos de texto. También se amplía la demostración: muestra cómo descomprimir un archivo XLSX en el navegador, entre otras cosas.
Entonces, aunque creo que tiene una utilidad e interés limitados, funciona. Supongo que funcionaría en Node.js.