Strona 1 z 1

Dekompresja danych [zlib]

Nowy postNapisane: środa, 30 czerwca 2010, 16:52
przez Gusław
Witam!

Jestem nowy na forum,a swoją przygodę z programowaniem zacząłem niedawno. Proszę więc o wyrozumiałość. :)

A więc:
Napisałem 'program' który loguje się na stronkę, wszystko cacy (obsługa ciastek itd.). Chcę, aby serwer zwracał do mnie informacje w postaci skompresowanej (wiadomo, przyspieszy to ściąganie o te kilka ms). No i tu się zaczynają schody.
Doczytałem,że świetnie radzi sobie z tym biblioteka zlib, więc ją ściągnąłem,dodałem do projektu, cacy. :)

Ale.. nie wiem czemu, ale nie mogę sobie poradzić z dekompresją danych ze strumienia (MemoryStream). Nie wiem jak pobrać wielkość (nie bijcie!) takiej zmiennej. Z dekompresją/kompresją plików poradziłem sobie i kod wygląda tak:

Kompresja:
Kod: Zaznacz cały
fstream plikplik_po_zpakowaniu;
plik.open("zakoduj.txt",ios::in|ios::binary);
plik.seekg(0,ios::end);
unsigned int dlugosc_pliku plik.tellg();
plik.seekg(0,ios::beg);
unsigned charbufor = new unsigned char[dlugosc_pliku];
for(
unsigned int i 0;i<dlugosc_pliku;i++)
{
plik.read((char*)&bufor[i],1);
}
unsigned long dlugosc_po_zpakowaniu dlugosc_pliku 15;
unsigned charbufor_docelowy = new unsigned char[dlugosc_po_zpakowaniu];
compress2(bufor_docelowy,&dlugosc_po_zpakowaniu,bufor,dlugosc_pliku,Z_BEST_COMPRESSION);
plik_po_zpakowaniu.open("zakodowany.zlib",ios::binary|ios::out);
for(
unsigned int i 0i<dlugosc_po_zpakowaniu;i++)
{
plik_po_zpakowaniu.write((char*)&bufor_docelowy[i],1);
}
plik.close();
plik_po_zpakowaniu.close();
 


Dekompresja:
Kod: Zaznacz cały
fstream plikplik_po_rozpakowaniu;
plik.open("zakodowany.zlib",ios::binary|ios::in);
plik.seekg(0,ios::end);
int dlugosc_pliku plik.tellg();
plik.seekg(0,ios::beg);
charbufor = new char[dlugosc_pliku];
for(
int i 0;i<dlugosc_pliku;i++)
{
plik.read((char*)&bufor[i],1);
}
unsigned long dlugosc_po_rozpakowaniu=100000;
charbufor_docelowy = new char[dlugosc_po_rozpakowaniu];
uncompress(bufor_docelowy,&dlugosc_po_rozpakowaniu,bufor,dlugosc_pliku);
plik_po_rozpakowaniu.open("rozpakowany.txt",ios::binary|ios::out);
for(
unsigned int i 0i<dlugosc_po_rozpakowaniu;i++)
{
plik_po_rozpakowaniu.write((char*)&bufor_docelowy[i],1);
}
plik.close();
plik_po_rozpakowaniu.close(); 


Działa to elegancko, ale raczej przeszkadzałoby mi tworzenie w locie takich małych pliczków, dekompresję itd. Więc moje pytanie brzmi:
Jak pobrać wielkość MemoryStream i później ją zdekompresować.


Pozdrawiam i dziękuję za uwagę. :)

P.S.
Trochę zagmatwałem, ale mam nadzieję, że zrozumieliście.

Re: Dekompresja danych [zlib]

Nowy postNapisane: środa, 30 czerwca 2010, 18:17
przez Cyfrowy Baron
Nie słyszałem o tym by archiwa zip obsługiwały dekompresję archiwów wczytanych do pamięci. Można co prawda pobrać dane z archiwum zip do strumienia, ale dane z pliku lokalnego, nie da się tego zrobić z plikiem na serwerze. Czyli normalnie to działa tak, masz plik na dysku lokalnym lub wymiennym, lub w sieci lokalnej i pobierasz z tego archiwum jakiś plik do pamięci, czyli np. do obiektu typu TMemoryStream, ale pobierasz konkretny plik z archiwum, a nie całe archiwum.

Jak rozumiem Ty chcesz pobrać archiwum z sieci do obiektu typu TMemoryStream, a potem chcesz z tego archiwum znajdującego się w pamięci wyciągnąć plik i przepisać do innego obiektu w pamięci?! Z tego co się orientuję to tak się nie da, gdyż sam kiedyś chciałem zrobić coś podobnego i bez skutku. Archiwa ZIP tego nie obsługują.

Inny sposób to nie wczytywanie do pamięci całego archiwum, a tylko pliku z archiwum. Jest to możliwe, w jednym ze swoich program bazę danych oparłem na tym mechanizmie. Nie działa to jednak dla plików znajdujących się w sieci. Możesz to zrobić tylko w ten sposób, że pobierasz plik z sieci, może być do pamięci, czyli np. do TMemoryStream, ale musisz go zapisać na dysku, a potem pobrać do pamięci plik z tego archiwum.

Nie wiem jak to zrobić dla ZLIB, gdyż używam ZipForge.




Jak pobrać wielkość MemoryStream


Kod: Zaznacz cały
TMemoryStream *mStream = new TMemoryStream();
int size = mStream->Size;


Archiwum znajdujące się w pamięci nie da się dekompresować, gdyż biblioteka ZLIB i chyba żadna inna do obsługi archiwów ZIP, RAR, CAB nie obsługuje takiej operacji. To nie jest kwestia klasy TMemoryStream, gdyż ta klasa wogóle nie obsługuje archiwów, a archiwum ZIP wczytane do pamięci traktuje jak każdy iny plik, to kwestia biblioteki ZLIB i jeżeli ta biblioteka nie ma takiej funkcji to nic nie zrobisz.

Re: Dekompresja danych [zlib]

Nowy postNapisane: środa, 30 czerwca 2010, 18:45
przez Gusław
Inaczej... Wiedziałem, że zagmatwam.

Używam IdHTTP i ustawiłem w nim Request->AcceptEncoding na: gzip,deflate. Jeśli byłoby ustawienie 'default'owe, czyli nic, to serwer zwraca czysty (nieskompresowany) kod źródłowy strony (html/php). Gdy ustawię tak jak napisałem wyżej, to serwer zwraca kod źródłowy strony w postaci skompresowanej- i o to mi chodzi.

Kod: Zaznacz cały
TStringStream *ODBIERA=new TStringStream("");
...
__try {Form1->IdHTTP1->Get(Form1->IdHTTP1->Response->Location,ODBIERA);} __except (2) {}


Ale ja dostaję te skompresowane źródło w StringStream,a funkcja potrzebuje bodajże bufora w postaci 'char'.
Więc zadam pytanie inaczej, jak można przekonwertować StringStream do char.

Info co do uncompress:
Kod: Zaznacz cały
int uncompress(Bytef *dest, uLongf *destLen, const Bytef*source, uLongf sourceLen);
dest – wskaźnik do bufora do którego zostaną rozpakowane dane
destLen – długość danych rozpakowanych. Wartość zwracana przez funkcje
source – wskaźnik do danych które mają być rozpakowane
sourceLen – długość danych które maja być rozpakowane


Pomieszałem trochę, jak to zwykle. Wybacz Baronie. :roll: ;)

Re: Dekompresja danych [zlib]

Nowy postNapisane: środa, 30 czerwca 2010, 20:53
przez Cyfrowy Baron
Nie mam tej biblioteki mogę więc tylko zgadywać.

Kod: Zaznacz cały

  TMemoryStream 
*mStream = new TMemoryStream();

  // pobierasz dane do mStream

  mStream->Seek(0, soFromBeginning);
  int size = mStream->Size;

 
 Byte[] Bufor = new Byte[size]; //lub char *Bufor = (char*)malloc(size); 
  
   mStream
->Read(Bufor, size); // lub mStream->ReadBuffer(Bufor, size);

 // dalej sam już wiesz
 


Nie sprawdzałem, gdyż nie mam wspomnianej biblioteki

Re: Dekompresja danych [zlib]

Nowy postNapisane: środa, 30 czerwca 2010, 21:07
przez polymorphism
Tak jak pokazał Baron, możesz użyć TMemoryStream, z tym że nie musisz kopiować danych z tego strumienia do specjalnie przygotowanego bufora, tylko od razu podać funkcji uncompress wskaźnik zwrócony przez właściwość Memory.

Re: Dekompresja danych [zlib]

Nowy postNapisane: niedziela, 11 lipca 2010, 14:45
przez Darek_C++
@Gusław - jakie biblioteki używasz do tej dekompresji gzip. Skąd ją można pobrać ?

Re: Dekompresja danych [zlib]

Nowy postNapisane: niedziela, 11 lipca 2010, 18:10
przez Cyfrowy Baron
Darek_C++ napisał(a):@Gusław - jakie biblioteki używasz do tej dekompresji gzip. Skąd ją można pobrać ?


Przecież masz to podane w pierwszym poście i w tytule wątku. Używa biblioteki ZLIB, ale to nie jest komponent.

Re: Dekompresja danych [zlib]

Nowy postNapisane: niedziela, 11 lipca 2010, 21:35
przez Darek_C++
Wiem, że to nie jest komponent dlatego też pytam Gustawa "Skąd ją można pobrać ?"

Re: Dekompresja danych [zlib]

Nowy postNapisane: niedziela, 11 lipca 2010, 21:42
przez Cyfrowy Baron