Сжатие файла перед загрузкой на стороне клиента - PullRequest
11 голосов
/ 04 декабря 2011

В основном я буду работать с большими файлами XML (примерно 20 - 50 МБ). Эти файлы должны быть загружены на сервер.

Я знаю, что невозможно ни прикоснуться к файлам с помощью JavaScript, ни реализовать HTTP-сжатие на стороне клиента.

Мой вопрос заключается в том, что если существует какое-либо решение (сценарий flash / action), которое сжимает файл и имеет JavaScript-API?

Сценарий таков:

  1. Попытка загрузить 50 МБ XML-файл
  2. Перед загрузкой захватите его с помощью Javascript и отправьте в компрессор.
  3. Загрузить сжатый файл вместо исходного.

Ответы [ 6 ]

5 голосов
/ 29 ноября 2015

Вы можете использовать JSZip .Для ввода он поддерживает String / ArrayBuffer / Uint8Array / Buffer , но not blob s, то есть то, что вы получаете от <input type="file"/> с javascript:

Объект File - это особый вид Blob, и его можно использовать в любом контексте, который может использовать Blob

(ссылка)

Итаквам нужно сначала конвертировать BLOB-файл / файл, например, в ArrayBuffer, например, используя FileReader.readAsArrayBuffer().Обратите внимание, что эта функция работает асинхронно, требуя использования обратного вызова.Также имеется FileReaderSync , однако «Этот интерфейс доступен только для рабочих, поскольку он позволяет синхронный ввод-вывод, который потенциально может блокировать», поэтому я не вижу никакого смысла в его использовании.

( РЕДАКТИРОВАТЬ. Я не уверен, но я думаю, что вы можете пропустить преобразование 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"].

5 голосов
/ 05 декабря 2011

Встроенная в Flash реализация ByteArray имеет метод (ByteArray::deflate для дефлирования содержимого (bytearray). Алгоритм deflate представляет собой Спецификация формата сжатых данных DEFLATE версии 1.3 .

Существует также метод ByteArray::compress, который сжимает с использованием алгоритма zlib

Постойте, я напишу вам пример кода для использования этого класса и открою его для JavaScript.

EDIT

Я загрузил файл в http://www.filefactory.com/file/cf8a39c/n/demo5.zip

РЕДАКТИРОВАТЬ 2 Для тех, кто не может загрузить файлы:

Мой код ActionScript в demo5.fla (скомпилирован в 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 голос
/ 21 августа 2012

Подумайте над просмотром этого другого сообщения stackoverflow .Чтение обоих ответов дает хорошее представление о реальности сжатия.

Я рассматриваю возможность внедрения решения Silverlight of Flex, которое сжимает клиентскую часть, и, если пользователь не хочет его устанавливать, сжимает и распаковывает файловый сервер.,Обновит этот пост, когда будет найдено решение.

Установка элемента управления будет продана пользователю в качестве экономии времени, что, как правило, верно.Для сервера это будет экономия пропускной способности и сжатия.

1 голос
/ 14 декабря 2011

С Silverlight вы можете архивировать файлы на стороне клиента, и этот подход работает во всех основных браузерах. Кроме того, вы можете взаимодействовать со своим виджетом Silverlight через JavaScript. Кроме того, если пользователю необходимо загрузить несколько файлов, ваш виджет Silverlight может отображать диалоговое окно single для выбора всех файлов. Единственным недостатком является то, что ваши клиенты должны установить плагин Silverlight.

1 голос
/ 05 декабря 2011

Если по какой-либо причине вы не можете получить решение для работы на JavaScript для всех основных браузеров, я знаю библиотеку сжатия AS3 здесь: http://code.google.com/p/ascompress/.

Кроме того, менее крутой вариант, если ваши целевые пользователи немного разбираются в технологиях, почему бы им не загрузить ZIP-файл XML? Затем на стороне сервера вы можете разархивировать и обработать при необходимости.

В любом случае на стороне сервера вы захотите распаковать / распаковать, что будет легко для Google, если у вас его еще нет.

0 голосов
/ 05 декабря 2011

Есть некоторая библиотека javascript сжатия Хаффмана, например, https://github.com/wilkerlucio/huffman_js, но я думаю, что ваша задача невозможна, потому что с javascript и html невозможно загрузить огромные данные в браузер или память клиента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...