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

时间:2011-12-04 17:45:57

标签: javascript flash flex upload compression

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

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

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

情景如下:

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

6 个答案:

答案 0 :(得分:5)

Flash内置的ByteArray实现有一个方法(ByteArray::deflate来缩小内容(bytearray)。deflate算法是DEFLATE Compressed Data Format Specification version 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];
    }
}

答案 1 :(得分:5)

您可以使用JSZip。对于输入,它支持String/ArrayBuffer/Uint8Array/Buffer,但不是 blob,这是您使用javascript从<input type="file"/>获得的内容:

  

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

(link)

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

编辑。我不确定,但我相信您现在可以跳过blob-&gt; 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"]

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

考虑查看其他stackoverflow post。阅读这两个答案描绘了压缩现实的良好画面。

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

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

答案 5 :(得分:0)

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