问题 在客户端上载之前进行文件压缩


基本上我将使用大型XML文件(大约20 - 50 MB)。这些文件需要上传到服务器上。

我知道用javascript触摸文件是不可能的,也不能在客户端实现HTTP压缩。

我的问题是,如果存在压缩文件并具有javascript API的任何解决方案(闪存/动作脚本)?

场景是这样的:

  1. 试图上传50 MB的XML文件
  2. 在上传之前,使用Javascript抓取它并将其发送到压缩器。
  3. 上传压缩文件而不是原始文件。

6544
2017-12-04 17:45


起源

我找到了这个,但我从未使用它(这里没有Flash): jszip.stuartk.co.uk - AsTheWormTurns
感谢您的链接,但基本上我需要一个适用于所有主流浏览器的解决方案,如IE7 +,FF,Safari和Chrome。 - feketegy


答案:


Flash的ByteArray内置实现有一个方法(ByteArray::deflate 放气(bytearray)的内容deflate算法是 DEFLATE压缩数据格式规范版本1.3

那里也是一个 ByteArray::compress 用压缩方法压缩的方法 zlib的 算法

稍等一下,我会给你写一些示例代码来使用这个类并将它暴露给JavaScript。

编辑

我上传了这个文件 http://www.filefactory.com/file/cf8a39c/n/demo5.zip

编辑2 对于那些无法下载文件的人:

我在demo5.fla中的ActionScript代码(编译为demo5.swf)

import flash.external.ExternalInterface;
import flash.net.FileReference;
import flash.events.Event;
import flash.utils.ByteArray;

if(ExternalInterface.available) {
    //flash.system.Security.allowDomain("localhost");
    ExternalInterface.addCallback("deflate", doDeflate);
    ExternalInterface.addCallback("compress", doCompress);
}

var method:String="deflate";
var b:ByteArray;
function doCompress(_data:String):void {
    method="compress";
    exec(_data);
}

function doDeflate(_data:String):void {
    method="deflate";
    exec(_data);
}

function exec(_data:String):void {
    b=new ByteArray();
    b.writeUTFBytes(_data);
    b.position=0;
    if(method=="compress") {
        b.compress();
    } else if(method=="deflate") {
        b.deflate();
    }
    executed();
}

function executed():void {
    if(ExternalInterface.available) {
        b.position=0;
        var str:String=b.readUTFBytes(b.bytesAvailable);
        ExternalInterface.call("onExec", str);
    }
}

我的HTML代码嵌入swf:

<button onclick="doDeflate()">Deflate</button>
<button onclick="doCompress()">Compress</button>
<div id="flashContent">
    <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="1" height="1" id="demo5" align="middle">
        <param name="movie" value="demo5.swf" />
        <param name="quality" value="high" />
        <param name="bgcolor" value="#ffffff" />
        <param name="play" value="true" />
        <param name="loop" value="true" />
        <param name="wmode" value="window" />
        <param name="scale" value="showall" />
        <param name="menu" value="true" />
        <param name="devicefont" value="false" />
        <param name="salign" value="" />
        <param name="allowScriptAccess" value="always" />

        <embed src="demo5.swf" quality="high" bgcolor="#869ca7"
             width="1" height="1" name="demo5" align="middle"
             play="true" loop="false" quality="high" allowScriptAccess="always"
             type="application/x-shockwave-flash"
             pluginspage="http://www.macromedia.com/go/getflashplayer">
        </embed>
    </object>
</div>

最后是javascript代码:

function doDeflate() {
    var data="fdg fhnkl,hgltrebdkjlgyu ia43uwriu67ri8m nirugklhvjsd fgvu";
    //DATA CONTAINS DATA TO BE DEFLATED
    thisMovie("demo5").deflate(data);
}

function doCompress() {
    var data="fdg fhnkl,hgltrebdkjlgyu ia43uwriu67ri8m nirugklhvjsd fgvu";
    //DATA CONTAINS DATA TO BE DEFLATED
    thisMovie("demo5").compress(data);
}

function onExec(data) {
    //DATA CONTAINS THE DEFLATED DATA
    alert(data);
}

function thisMovie(movieName) {
    if (navigator.appName.indexOf("Microsoft") != -1) {
        return window[movieName];
    } else {
        return document[movieName];
    }
}

5
2017-12-05 12:49



谢谢,我在等它。 :)此外,使用Flash的文件处理是否容易?我猜是为了获取你需要使用Flash文件对话框的文件,然后压缩它然后以某种方式将它发送到服务器... - feketegy
@feketegy,我在32分钟前添加了上传(不知道为什么我之后添加的评论没有发布)。无论如何,它中的html包含非常自我解释的javascript(带注释)所以如果你什么都没有得到,请不要犹豫。但有一个问题是:你将不得不在http://域上运行html或者为你的flash播放器添加一个例外(你的选择) - Pranav Hosangadi
多亏了这个,我也可以将文件从<input type =“file”/>传递给flash吗?在javascript中我只能访问文件的路径而没有别的。因此,一旦文件被压缩,您建议如何将其发送到服务器? - feketegy
啊!!该函数需要文件的内容,而不是路径。这是因为Flash(来自浏览器)无法读取文件,除非它是由用户交互(如点击或按键)触发的。或者,您可以在Flash中创建整个上传器。我很快就会上传这样的例子 - Pranav Hosangadi
看到 livedocs.adobe.com/flex/3/html/... 有关如何构建上传器的说明(抱歉我无法上传我的代码,因为我很难及时)它非常简单 - Pranav Hosangadi


你可以利用 JSZip。对于输入,它支持 字符串/ ArrayBuffer / Uint8Array /缓冲器但是   blobs,这是你得到的 <input type="file"/> 用javascript:

File对象是特定种类的Blob,可以在Blob可以使用的任何上下文中使用

(链接)

因此,您必须将blob /文件转换为例如首先是ArrayBuffer,例如运用 FileReader.readAsArrayBuffer()。请注意,此函数异步工作,要求回调使用。还有一个 FileReaderSync 可用,但“此接口仅在工作人员中可用,因为它启用了可能阻止的同步I / O”,因此我认为使用它没有任何好处。

编辑。我不确定,但我相信你现在可以跳过blob-> ArrayBuffer转换,只需压缩File对象。

如果php的指令,这整个方法特别有用 max_file_uploads 由您的网站空间主机设置为一个小数字,现在您唯一需要担心的是 upload_max_filesize

作为参考,下面是一个代码示例摘录(使用 JQuery)用于放置一个文件 multiple 在提交之前以zip方式输入文件:

// onclick:
var fileInput = $(':file');
var files = [];
$.each(fileInput[0].files, function(i, file) {
    files.push(file);
});

var zip = new JSZip();
function addFileToZip(n) {
    if(n >= files.length) {
        zippingComplete(zip.generate({type:"blob", compression:"deflate"}));
        return;
    }
    var file = files[n];                    
    var arrayBuffer;
    var fileReader = new FileReader();
    fileReader.onload = function() {
        arrayBuffer = this.result;
        zip.file(file.name, arrayBuffer);
        addFileToZip(n + 1);
    };
    fileReader.readAsArrayBuffer(file);
}
addFileToZip(0);

function zippingComplete(zip) {
    formData = new FormData();
    formData.append('fileZip', zip);
    formData.append("param1", "blah");
    $.ajax({
        data: formData,
        //... etc

服务器方面,您将访问 $_FILES["fileZip"]


4
2017-11-29 15:19



您可以跳过版本3+中的blob-> ArrayBuffer转换。但对于旧版本(在我的情况下为2.6),您的解决方案非常有用 - Obi-Wan Spock


如果由于某种原因你无法获得所有主流浏览器的JavaScript解决方案,我在这里知道一个AS3压缩库: http://code.google.com/p/ascompress/

另外,一个不太酷的选项,如果你的目标用户有点技术讽刺,为什么不让他们上传xml的.zip文件?然后在服务器端,您可以根据需要解压缩和处理。

无论哪种方式在服务器端你都想要解压缩/解压缩,如果你还没有想到解决方案,这应该很容易google解决方案。


1
2017-12-05 03:44



谢谢你的链接。此解决方案是否具有Javascript API?我不熟悉Flash / Actionscript(我只是一个用户)。此外,我不能让用户事先压缩XML文件。不幸的是,这必须是一个自动化过程,尽管这将是理想的... - feketegy
您可以在ActionScript中处理所有这些内容,因为它拥有自己的文件浏览器。如果您因为任何原因需要它与JavaScript交谈,尽管您可以使用AS3的ExternalInterface。 Pranav有一个很好的解决方案。 - ToddBFisher


使用Silverlight,您可以在客户端压缩文件,这种方法适用于所有主流浏览器。此外,您可以通过JavaScript与Silverlight小部件进行交互。此外,如果用户需要上传多个文件,您的Silverlight小部件可以显示  用于选择所有文件的对话框。唯一的缺点是您的客户必须安装Silverlight插件。


1
2017-12-14 16:25





考虑回顾一下这个 stackoverflow帖子。阅读这两个答案描绘了压缩现实的良好画面。

我正在考虑实现压缩客户端的Silverlight of Flex解​​决方案,如果用户不想安装它,请压缩和解压缩文件服务器端。将在找到解决方案时更新此帖子。

安装控件将作为节省时间出售给用户,这通常是正确的。对于服务器,它将是带宽和压缩处理保护程序。


1
2017-08-21 05:21





例如,有一些免费提供的霍夫曼压缩javascript库 https://github.com/wilkerlucio/huffman_js 但我认为你的任务是不可能的,因为使用javascript和html,无法将大量数据加载到浏览器或客户端的内存中。


0
2017-12-04 23:47



嘿,谢谢,但正如我在上一篇评论中提到的,我需要一个适用于IE7 +和其他主流浏览器的解决方案。这个解决方案在某种程度上是一个实验性的Javascript,我认为它不能处理40到50 MB的大型XML文件。 - feketegy
@feketegy:这只是一个建议。你可以自己做。 - Bytemain
看一下这个 gildas-lormeau.github.io/zip.js - Matthew Lock