2013-07-26 13 views
19

Mam aplikację internetową (ruby na szynach), która wysyła trochę YAML jako wartość ukrytego pola wejściowego.Kompresja dużego ciągu w rubinie

Teraz chcę zmniejszyć rozmiar tekstu przesyłanego do przeglądarki. Jaka jest najskuteczniejsza forma bezstratnej kompresji, która byłaby przesyłana przez minimalne dane? Mogę ponieść dodatkowy koszt kompresji i dekompresji po stronie serwera.

Odpowiedz

47

Można użyć realizację zlib w rdzeniu ruby ​​w/danych de-Flate:

require "zlib" 
data = "some long yaml string" * 100 
compressed_data = Zlib::Deflate.deflate(data) 
#=> "x\x9C+\xCE\xCFMU\xC8\xC9\xCFKW\xA8L\xCC\xCDQ(.)\xCA\xCCK/\x1E\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15D\x15\x04\x00\xB3G%\xA6" 

Należy base64 zakodować dane skompresowane, aby druku:

require 'base64' 
encoded_data = Base64.encode64 compressed_data 
#=> "eJwrzs9NVcjJz0tXqEzMzVEoLinKzEsvHhUcFRwVHBUcFRwVHBUcFUQVBACz\nRyWm\n" 

Później , po stronie klienta możesz użyć pako (port zlib do javascript), aby odzyskać dane. This answer prawdopodobnie pomaga w implementacji części JS.

Aby dać wyobrażenie o tym, jak skuteczne jest to, tutaj są rozmiary przykładowych ciągów:

data.size   # 2100 
compressed_data.size # 48 
encoded_data.size # 66 

samo idzie odwrotnie podczas kompresji na kliencie i pompowania na serwerze.

Zlib::Inflate.inflate(Base64.decode64(encoded_data)) 
#=> "some long yaml stringsome long yaml str ... (shortened, as the string is long :) 

Zastrzeżenie:

  • Ruby zlib realizacja powinny być zgodny z implementacją Pako. Ale nie próbowałem tego.
  • Liczby dotyczące rozmiarów napisów są trochę oszukane. Zlib jest tutaj naprawdę skuteczny, ponieważ ciąg powtarza się dużo. Prawdziwe dane z życia zazwyczaj nie powtarzają się tak bardzo.
+2

To szwy, które głosowałem to przypadkowo kilka dni temu, ponieważ nie pamiętam, aby to zrobić. Jeśli zechcesz, zrób edycję, aby wycofać moje przypadkowe głosowanie :( – Krule

+2

@Krule dzięki za bycie miłym.Najpierw nie byłem pewien, czy znajdę użyteczną aktualizację, ale potem natknąłem się na pako, które (wydaje się) jest o wiele lepszą biblioteką zlib js niż zlib.Tak więc dzięki za przypomnienie, aby spojrzeć na moją odpowiedź ponownie, mógłbym ją poprawić :) – tessi

+4

Proszę zauważyć, że wynik 'Zlib :: Deflate.deflate' nie jest zgodny z formatem że program narzędziowy 'gzip' generuje i nie będzie akceptowany przez' gunzip', który oczekuje pewnych danych nagłówka przed skompresowaną zawartością. Jeśli chcesz odczytać wynik za pomocą 'gunzip', użyteczny będzie następujący kod:' Zlib :: Deflate.new (zero, 31) .deflate (data, Zlib :: FINISH) ' – Guss