【问题标题】:Ungzip csv files in web browser with javascript使用 javascript 在 Web 浏览器中解压缩 csv 文件
【发布时间】:2014-06-30 12:28:23
【问题描述】:

我想从网络服务器下载压缩后的 csv 文件,然后在浏览器中解压缩。

到目前为止,我已经尝试使用pakozlib 在我的服务器上获取压缩文件,但遇到了各种问题。尝试解压缩 unix-gzip 压缩文件时,我不断收到错误的标头消息。

接下来,我尝试使用 node 将文件压缩到服务器上,目前出现此错误

Uncaught Error: invalid file signature:,�

这是我用来获取文件的命令:

$.ajax({ type: "GET", url: 'public/pols_zlib.csv.gz'})
  .done(function(d){
    var gunzip = new Zlib.Gunzip(d);
    plain = gunzip.decompress(); 
  });

我正在寻找在我的服务器上压缩文件并在浏览器中解压缩的任何方法。

【问题讨论】:

  • 在 HTTP 级别进行压缩,让浏览器在后台负责解压。
  • quentin,在 ajax 调用中到底是什么样的?
  • 就像一个压缩数据的负载,响应头说它是压缩的。
  • @Quentin 这是否意味着我需要更改为压缩文件提供服务的服务器上的某些内容?或者,我可以在 javascript 调用中设置它吗?在这种情况下,我不控制服务器选项,因此更改服务器发送文件的方式并不是一个真正的选择。无论解决方案是什么,都必须使用 javascript。
  • 也许您需要一个服务器端脚本来生成带有正确标头的 HTTP 响应,并将您的 CSV 文件写入响应流。您熟悉任何服务器端技术吗?

标签: javascript browser zlib


【解决方案1】:

您不需要在服务器上压缩 .csv 文件(除非您的主要目标是节省服务器上的磁盘空间)。此答案假定您的目标是减少将 .csv 文件下载到客户端所需的时间。

正如 Quentin 上面提到的,所有现代 Web 服务器都会为您处理在线压缩。这意味着 .csv 文件(以及所有基于文本的文档)可以在发送到客户端之前进行压缩。客户端(Web 浏览器)然后为您解压缩文件。为了确保这些东西正常工作,您可以使用Fiddler 之类的工具来嗅探 HTTP 流量。此屏幕截图显示了如何使用 GZIP 压缩此网页。

为确保使用压缩,服务器和客户端都需要使用 HTTP 标头“宣传”事实。在客户端,这可以使用 ajax 来完成,如下所示:

$.ajax({
  ...
  headers: { "Accept-Encoding" : "gzip" },
  ...
});

如果服务器启用了压缩,它会响应以下 http 标头:

Content-Encoding: gzip

在 Fiddler 中可以看到:

您可以阅读更多关于 HTTP 压缩的信息here

最后,我建议打开/关闭 HTTP 压缩并使用 Fiddler 对结果进行基准测试。

【讨论】:

  • 在这种情况下,我无法控制服务器,我上传的文件需要小于一定大小才能上传。这就是为什么所有的解压都必须在 javascript 中完成,而我无法更改服务器的回复方式。在这种情况下,服务器不会回复正确的标头,从而使浏览器自动解压缩文件。此外,jquery 不会设置接受编码,错误消息是它是一个不安全的标头。
  • 我明白了。在这种情况下,这个来自另一个线程的响应可能是您正在寻找的:stackoverflow.com/a/5633128/139774 它讨论了 JSXCompressor 的使用,它可以在客户端解压缩。
【解决方案2】:

需要browser to support typedarrays 的纯二进制解决方案的另一个答案。使用这种方法,不需要使用 base64 编码,从而允许更小的文件大小。当不需要旧版浏览器支持时,建议使用此解决方案。

下载并添加对pako_inflate.min.js的引用。

这是我测试过的 HTML。

<html>
<head>
    <title>Binary Example</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="~/Scripts/pako_inflate.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        var oReq = new XMLHttpRequest();
        oReq.open("GET", 'file.csv.gz?_=' + new Date().getTime(), true);
        oReq.responseType = "arraybuffer";
        oReq.onload = function (oEvent) {
            var arrayBuffer = oReq.response; // Note: not oReq.responseText
            if (arrayBuffer) {
                var byteArray = new Uint8Array(arrayBuffer);
                var data = pako.inflate(byteArray);
                //$('body').append(String.fromCharCode.apply(null, new Uint16Array(data)));  // debug
                $('#link').attr("href", "data:text/csv;base64," + btoa(String.fromCharCode.apply(null, new Uint16Array(data))));
            }
        };
        oReq.send(null);
    </script>
</head>
<body>
    <a id="link" download="file.csv">file</a>
</body>
</html> 

【讨论】:

    【解决方案3】:

    我相信我之前的答案很有价值,所以我在这里创建一个单独的答案来解决这个更具体的用例。条件是:

    1. 无法控制服务器
    2. 在上传之前必须限制 csv 的文件大小
    3. 服务器未使用 gzip 对 csv 进行编码

    我建议在客户端使用JSXCompressor 库来解码 javascript 中的 gzip 文件。

    但是,gzip 文件必须首先进行 base64 编码。以下 linux 命令将执行此操作:

    gzip -c file.csv | base64 > file.csv.gz.txt
    

    我建议使用 .txt 文件扩展名来确保服务器像处理文本一样处理它。

    由于我使用 DataURI 下载 csv(见下文),您可以在 gzip 压缩之前对其进行 base64 编码以保存在客户端上执行的操作。但是,它会增加文件大小(您试图避免这种情况)。

    文件经过 gzip 和 base64 处理后,即可上传到服务器。请注意,base64 会增加大量开销,但这是必需的。较小的文件更明显:

    uncompressed:        91 kB
    compressed:          38 kB
    compressed + base64: 72 kB
    
    uncompressed:        8.2 MB
    compressed:          1.9 MB
    compressed + base64: 2.6 MB
    

    这里是 HTML 标记。这是我测试过的一个工作示例。

    <html>
    <head>
        <title>Working Example</title>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="jsxcompressor.min.js" type="text/javascript"></script>
        <script type="text/javascript">
            $.ajax({
                url: "/file.csv.gz.txt",
                cache: false
            })
                .done(function (b64file) {
                    // $('body').append(b64file);  // debug
                    var binary = JXG.decompress(b64file);
                    $('#link').attr("href", "data:text/csv;base64," + btoa(binary));
                });
        </script>
    
    </head>
    <body>
        <a id="link" download="file.csv">file</a>
    </body>
    </html> 
    

    【讨论】:

    • 很高兴它成功了。我为纯二进制解决方案添加了另一个答案,如果您不需要支持旧版浏览器,则可以省略 base64 步骤(从而减少文件大小)。
    【解决方案4】:

    谷歌搜索“在 php 和 js 中压缩和解压缩”给了我这个:

    【讨论】:

    • 不幸的是,这些问题的答案是导致无效文件签名问题的原因。
    【解决方案5】:

    您遇到此问题是因为 ajax 将响应标题文本/html。

    也许这样的事情可以帮助你:

    jQuery File Download Plugin for Ajax

    【讨论】:

    • 感谢您的回答!不幸的是,这里的问题是使用浏览器中的文件信息,而不是下载文件,所以这个插件不能解决问题。
    • 但是使用这个插件你不会下载文件,你将把文件内容放入一个变量中,就像你进行 ajax 调用一样。
    猜你喜欢
    • 2019-03-23
    • 2023-04-05
    • 2017-03-15
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多