解压文件

IT技术 javascript zip unzip
2021-02-05 19:53:41

我想使用 Web 浏览器在客户端显示OpenOffice文件、.odt 和 .odp。

这些文件是压缩文件。使用 Ajax,我可以从服务器获取这些文件,但这些文件是压缩文件。我必须使用JavaScript解压缩它们,我尝试使用 inflate.js,http: //www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt ,但没有成功。

我怎样才能做到这一点?

6个回答

我用 Javascript 写了一个解压器。有用。

它依赖于Andy GP Na 的二进制文件阅读器一些来自 notmasteryet 的 RFC1951 膨胀逻辑我添加了 ZipFile 类。

工作示例:
http : //cheeso.members.winisp.net/Unzip-Example.htm(死链接)

来源:
http : //cheeso.members.winisp.net/srcview.aspx?dir=js-unzip(死链接)

注意:链接已失效;我很快就会找到一个新的主人。

源代码中包含一个 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));
    }
}

该演示分几个步骤进行:readFilefn 由单击触发,并实例化一个 ZipFile 对象,该对象读取 zip 文件。读取完成时有一个异步回调(对于合理大小的 zip,通常会在不到一秒的时间内发生) - 在这个演示中,回调保存在 doneReading 局部变量中,它只是调用extractEntries,它只是盲目地解压缩所提供的所有内容压缩文件。在真实的应用程序中,您可能会选择一些要提取的条目(允许用户选择,或以编程方式选择一个或多个条目等)。

extractEntries在所有条目FN迭代,并呼吁extract()各一个,通过一个回调。一个条目的解压需要时间,对于 zipfile 中的每个条目可能需要 1 秒或更长时间,这意味着异步是合适的。提取回调只是将提取的内容添加到页面上的 jQuery 手风琴中。如果内容是二进制的,那么它会被格式化(未显示)。


它有效,但我认为实用性有限。

一方面:它非常慢。从 PKWare 解压 140k AppNote.txt 文件需要大约 4 秒。在 .NET 程序中,同样的解压缩可以在不到 0.5 秒的时间内完成。 编辑:在 IE9 和 Chrome 中,Javascript ZipFile 的解包速度比现在快得多。它仍然比编译的程序慢,但对于正常的浏览器使用来说已经足够快了。

另一个:它不做流媒体。它基本上将 zipfile 的全部内容放入内存中。在“真实”的编程环境中,您只能读取 zip 文件的元数据(例如,每个条目 64 字节),然后根据需要读取和解压缩其他数据。据我所知,在 javascript 中没有办法像这样执行 IO,因此唯一的选择是将整个 zip 读入内存并在其中进行随机访问。这意味着它会对大型 zip 文件的系统内存提出不合理的要求。对于较小的 zip 文件来说问题不大。

另外:它不处理“一般情况”的 zip 文件——有很多 zip 选项我没有费心在解压器中实现——比如 ZIP 加密、WinZip 加密、zip64、UTF-8 编码的文件名等等在。编辑- 它现在处理 UTF-8 编码的文件名)。不过,ZipFile 类处理基础知识。其中一些事情并不难实施。在 Javascript 中一个 AES 加密类可以集成以支持加密。对于大多数 Javascript 用户来说,支持 Zip64 可能没用,因为它旨在支持 >4gb 的 zipfiles - 不需要在浏览器中提取它们。

我也没有测试解压二进制内容的情况。现在它解压缩文本。如果你有一个压缩的二进制文件,你需要编辑 ZipFile 类来正确处理它。我不知道如何干净地做到这一点。 它现在也处理二进制文件。


编辑- 我更新了 JS 解压缩库和演示。除了文本之外,它现在还处理二进制文件。我已经使它更具弹性和更通用 - 您现在可以指定在读取文本文件时使用的编码。演示也得到了扩展 - 它显示了在浏览器中解压缩 XLSX 文件等。

所以,虽然我认为它的实用性和兴趣有限,但它确实有效。我想它可以在 Node.js 中工作。

@Giulio - 好的,我修改了 ZipFile 类以支持对 UTF8 编码的文件名进行解码。它现在应该可以工作了。
2021-03-15 19:53:41
这看起来不错,但我收到此错误消息:此 zipfile 使用 UTF8,ZipFile.js 不支持。您可以推荐任何快速解决方法吗?
2021-03-24 19:53:41
@DannyBeckett - 好的,感谢您的提醒和建议。我很快就会把演示放在某个地方。
2021-03-25 19:53:41
刚刚得到一个声称链接已死的标志。你能再检查一下,然后把代码放在你的 SO 答案中吗?您将获得 30,000 个字符。如果这还不够,请发布第二个答案。这些链接继续下降没有任何好处。
2021-03-31 19:53:41
我有一个在线演示的旧版本,但我来这里是为了寻找更新。@Cheeso 有时间时会对更新的链接感兴趣。
2021-04-02 19:53:41

我正在使用zip.js,它似乎非常有用。值得一看!

例如,检查解压缩演示

我没有使用 Safari 的经验。您应该询问 zip.js 开发人员。项目页面底部有一个电子邮件地址:gildas-lormeau.github.com/zip.js也许这是一个错误,所以他们会感谢你的通知。
2021-03-18 19:53:41
我使用的 zip.js 与您使用的相同,但在 safari 中我没有定义文件阅读器。请帮助我使用 safari。
2021-03-25 19:53:41
我有 JSON 文件,其中包含 zip 格式的 base64 编码的 JSON 字符串。我需要那个内部 JSON 对象。Java的InflatorInputStream可以在服务器上解压,所以其实是zip格式的。但是,当我使用 BlobReader 将解码的 base64 数据从 atob() 传递到 zip.js 时,出现“读取 zip 文件时出错”。错误。从视觉上看,来自 atob() 的输出是二进制的,所以 BlobReader 似乎是正确的,无论如何都尝试了 TextReader,它给出了“文件格式无法识别。”。有任何想法吗?
2021-03-30 19:53:41
感谢您的回复,我已经发布了一个问题。
2021-04-06 19:53:41
pako在一行代码中解决了我的问题 pako.inflate(binaryData, { to: 'string' })
2021-04-08 19:53:41

我发现jszip非常有用。到目前为止,我仅用于阅读,但它们也具有创建/编辑功能。

代码明智它看起来像这样

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

我注意到的一件事是文件似乎必须是二进制流格式(使用 FileReader() 的 .readAsArrayBuffer 读取,否则我会收到错误消息,说我可能有一个损坏的 zip 文件

编辑:从 2.x 到 3.0.0 升级指南的注意事项

load() 方法和带有数据的构造函数(new JSZip(data))已被 loadAsync() 替换。

感谢用户2677034

该方法在JSZip 3.0中已被移除,请查看升级指南。
2021-03-16 19:53:41
谢谢伙计,这是一个了不起的库,因为它非常易于使用(与之前的答案相比)!
2021-03-30 19:53:41

如果您还需要支持其他格式或只需要良好的性能,您可以使用这个WebAssembly 库

它是基于Promise的,它使用 WebWorkers 进行线程处理,API 实际上是简单的 ES module

我写了“JavaScript 二进制工具”,这是一个开源项目,包括解压、解压和解压功能:https : //github.com/codedread/bitjs

在我的漫画书阅读器中使用:https : //github.com/codedread/ktoom(也是开源的)。

哼!