2011-12-04 32 views
9

Zasadniczo będę pracował z dużymi plikami XML (około 20 - 50 MB). Pliki te należy przesłać na serwer.Kompresja plików przed przesłaniem po stronie klienta

Wiem, że nie można dotknąć plików za pomocą javascript ani zaimplementować kompresji HTTP po stronie klienta.

Moje pytanie brzmi: czy istnieje jakieś rozwiązanie (skrypt flash/action), które kompresuje plik i ma interfejs API javascript?

Scenariusz jest taki:

  1. Próbuje załadować 50 MB plik XML
  2. Przed przesłać Skorzystaj z JavaScript i wysłać go do sprężarki.
  3. Prześlij skompresowany plik zamiast oryginalnego.
+0

Znalazłem to, ale nigdy go nie używałem (i nie Flash tutaj): http://jszip.stuartk.co.uk/ – AsTheWormTurns

+0

Dzięki za link, ale w zasadzie potrzebowałbym rozwiązania, które działa we wszystkich głównych przeglądarkach takich jak jak IE7 +, FF, Safari i Chrome. – feketegy

Odpowiedz

5

wbudowana wdrożenie Flasha z ByteArray ma metodę (ByteArray::deflate aby opróżnić zawartość (o ByteArray) Algorytm deflate jest DEFLATE Compressed Data Format Specification version 1.3

Istnieje S również ByteArray::compress metoda, która ściska za pomocą algorytmu

zlib

Poczekaj trochę, będę pisać ci przykładowy kod aby skorzystać z tej klasy i narazić go na JavaScript.

EDIT

został przesłany plik w http://www.filefactory.com/file/cf8a39c/n/demo5.zip

EDIT 2 Dla tych, którzy nie mogli pobrać pliki:

mojego kodu ActionScript w demo5.fla (skompilowany do 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); 
    } 
} 

Mój kod HTML osadzić 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> 

i wreszcie kod 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]; 
    } 
} 
+0

Dzięki, czekam na to. :) Ponadto, czy łatwo jest pracować z obsługą plików Flash? Zgaduję, aby uzyskać plik potrzebny do użycia okna dialogowego pliku Flash, a następnie skompresować go, a następnie wysłać go na serwer ... – feketegy

+0

@feketegy, Dodałem przesłanie jakieś 32 minuty temu (nie wiem dlaczego komentarz, który dodałem po tym, nie został opublikowany). W każdym razie, html w nim zawiera dość objaśniający javascript (z komentarzami), więc jeśli nic nie dostaniesz, nie wahaj się zapytać. Jednak jeden haczyk: będziesz musiał uruchomić kod HTML przez domenę http: // lub dodać wyjątek do swojego Flash Playera (Twój wybór) –

+0

Dzięki za to, również mogę przekazać plik z , do lampy błyskowej? W javascript mam tylko dostęp do ścieżki pliku i nic więcej. Skoro plik jest skompresowany, co sugerujesz, jak wysłać go na serwer? – feketegy

0

jakiś javascript biblioteka Huffman kompresji swobodnie dostępne np https://github.com/wilkerlucio/huffman_js ale myślę, że naszym zadaniem jest niemożliwe, ponieważ z JavaScript i HTML nie jest możliwe, aby załadować ogromne danych do pamięci przeglądarki lub klienta.

+0

Hej, dziękuję, ale jak wspomniałem w poprzednim komentarzu, potrzebuję rozwiązania, które działa IE7 + i innych głównych przeglądarek. To rozwiązanie jest w pewnym sensie eksperymentalnym Javascriptem, który, jak sądzę, nie jest w stanie obsłużyć dużych plików XML w zakresie 40 - 50 MB. – feketegy

+0

@feketegy: To tylko sugestia. Możesz zrobić to samemu. – Bytemain

+0

sprawdź to http://gildas-lormeau.github.io/zip.js/ –

1

Jeśli z jakiegoś powodu nie można znaleźć rozwiązania do pracy w JavaScript dla wszystkich głównych przeglądarek, znam bibliotekę kompresji AS3 tutaj: http://code.google.com/p/ascompress/.

Co więcej, mniej interesująca opcja, jeśli Twoi docelowi użytkownicy są nieco systernami technicznymi, dlaczego nie mieliby załadować pliku .zip pliku xml? Następnie po stronie serwera można rozpakować i przetworzyć w razie potrzeby.

Tak czy inaczej po stronie serwera będziesz chciał rozpakować/rozpakować, co powinno być łatwe do znalezienia rozwiązań w Google, jeśli jeszcze tego nie masz. .

+0

dziękuję za link. Czy to rozwiązanie ma interfejs API JavaScript? Nie znam się na Flashu/Actionscript (jestem tylko użytkownikiem). Nie mogę też pozwolić, aby użytkownicy wcześniej skompresowali pliki XML. Niestety musi to być zautomatyzowany proces, chociaż byłoby to idealne ... – feketegy

+0

Możesz obsłużyć wszystkie w ActionScripcie, ponieważ ma on własną przeglądarkę plików. Jeśli byłbyś potrzebny, aby porozmawiać z JavaScript z jakiegokolwiek powodu, możesz użyć zewnętrznego interfejsu AS3. Pranav ma fajne rozwiązanie powyżej. – ToddBFisher

1

z Silverlight, można zip plików po stronie klienta, a to podejście działa we wszystkich głównych przeglądarkach. Co więcej, możesz korzystać z widgetu Silverlight za pomocą JavaScript. Ponadto, jeśli użytkownik musi przesłać kilka plików, widżet Silverlight może wyświetlać jedno okno dialogowe pojedynczego w celu wybrania wszystkich plików. Jedyną wadą jest to, że twoi klienci muszą zainstalować wtyczkę Silverlight.

1

Rozważ omówienie tego innego stackoverflow post. Czytanie obu odpowiedzi daje dobry obraz rzeczywistości kompresji.

Rozważam wdrożenie rozwiązania Silverlight of Flex, które kompresuje stronę klienta i jeśli użytkownik nie chce go instalować, kompresuje i dekompresuje stronę serwera plików. Aktualizuje ten wpis po znalezieniu rozwiązania.

Zainstalowanie kontrolki zostanie sprzedane użytkownikowi jako oszczędność czasu, co zwykle jest prawdą. Dla serwera będzie to wygaszacz przetwarzania przepustowości i kompresji.

4

Możesz skorzystać z JSZip. Dla wejścia, obsługuje String/ArrayBuffer/Uint8Array/Buffer, ale nieblob s, co jest, co można uzyskać z <input type="file"/> z javascript:

Obiekt File jest specyficzny rodzaj Blob, i mogą być używane w dowolnym kontekście, że blob może

(link)

Więc trzeba przekształcić blob/plik do np najpierw ArrayBuffer, np. przy użyciu FileReader.readAsArrayBuffer(). Zauważ, że ta funkcja działa asynchronicznie, wymagając użycia wywołania zwrotnego. Dostępna jest również wersja FileReaderSync "Ten interfejs jest dostępny tylko dla pracowników, ponieważ umożliwia synchroniczne operacje we/wy, które mogą potencjalnie blokować", więc nie widzę żadnego pożytku z jego używania.

(EDIT. Nie jestem pewien, ale wierzę, że można pominąć blob-> konwersji ArrayBuffer teraz i po prostu zip obiekt File.)

Cała ta jest szczególnie przydatna podejście jeśli dyrektywa PHP max_file_uploads było zestaw do niewielkiej liczby przez gospodarza Przestrzeń, na razie jedyną rzeczą, którą musisz się martwić o to upload_max_filesize

dla porównania, wielkość próbki kodu następujący fragment (używając JQuery) za wprowadzenie kilku plików z jednego wejścia multiple w pliku zip przed przesłaniem:

// 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 

Po stronie serwera uzyskasz dostęp do $_FILES["fileZip"].

+0

można pominąć konwersję blob-> ArrayBuffer w wersji 3+. Ale dla starszej wersji (2.6 w moim przypadku) twoje rozwiązanie było bardzo pomocne –

Powiązane problemy