Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

problemy z tworzeniem programów do obsługi sieci, internetu, e-mail itp..

Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez Cyfrowy Baron » czwartek, 15 stycznia 2009, 11:03

Mam obiekt typu IStream i chciałbym przepisać jego zawartość do obiektu typu TMemoryStream lub do typu TStream.
Pobranie danych do obiektu typu IStream nie nastręcza mi problemów, ale nie mogę w żaden sposób przepisać jego zawartości do innego typu:

Kod: Zaznacz cały
     AnsiString Url ="http://cyfbar.republika.pl/images/img1.jpg";

     IStream* pStream;

     URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, 0);

    TStream *stream;
    // jak przepisać pStream do stream

   TMemoryStream *mStream = new TMemoryStream;
   // jak przepiać pStream do mStream
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez Witold » czwartek, 15 stycznia 2009, 17:27

Avatar użytkownika
Witold
Konstrukcjonista
Konstrukcjonista
 
Posty: 223
Dołączył(a): piątek, 29 sierpnia 2008, 10:53
Podziękował : 1
Otrzymał podziękowań: 14
Kompilator: bcb6, Turbo C++ Explorer
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez Cyfrowy Baron » czwartek, 15 stycznia 2009, 20:00

W przytoczonym przez ciebie linku nie ma nic o TMemoryStream ani TStream, a nie mogę użyć przedstawionej tam funkcji LoadFromIStream gdyż TMemoryStream i TStrem nie mają takich funkcji.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez polymorphism » czwartek, 15 stycznia 2009, 21:14

A co za problem napisać wrapper na IStream?

Coś w tym stylu:
Kod: Zaznacz cały
class CIStreamWrapper:public TStream
{
private:
   IStream*   m_stream;
public:
   virtual int __fastcall Read(void *Buffer, int Count) { ... }
   virtual int __fastcall Write(const void *Buffer, int Count) { ... }
   virtual int __fastcall Seek(int Offset, Word Origin) { ... }
   virtual __int64 __fastcall Seek(const __int64 Offset, TSeekOrigin Origin) { ... }
   //...itd

   CIStreamWrapper(IStream &ps) : m_stream(&ps)
   {
      m_stream->AddRef();
   }
   
   ~CIStreamWrapper()
   {
      m_stream->Release();
   }
};
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez kinio » czwartek, 15 stycznia 2009, 23:49

Witam!
Cyfrowy Baron napisał(a):Mam obiekt typu IStream i chciałbym przepisać jego zawartość do obiektu typu TMemoryStream lub do typu TStream.
Pobranie danych do obiektu typu IStream nie nastręcza mi problemów, ale nie mogę w żaden sposób przepisać jego zawartości do innego typu:

Najłatwiej to zrobić sobie jakiś buforek pośredni. Mi udało się coś takiego napisać i nawet ściąga ten obrazek - pewnie o to chodziło :)
Kod: Zaznacz cały
AnsiString Url ="http://cyfbar.republika.pl/images/img1.jpg";

     IStream* pStream;

     URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, 0);

     LARGE_INTEGER liZero = { 0 };      // Aby odnosic sie wzgledem poczatku strumienia
     ULARGE_INTEGER CurPos;             // Do zapisania pozycji wskaznika

     // Zapisujemy bierzaca pozycje wskaznika
     pStream->Seek(liZero, STREAM_SEEK_CUR, &CurPos);

     // Sprawdzamy wielkosc stumienia
     ULARGE_INTEGER SizeOfFile;
     pStream->Seek(liZero, STREAM_SEEK_END, &SizeOfFile);

     // Przywracamy wskaznik na poprzednia pozycje
     LARGE_INTEGER Pos;
     Pos.QuadPart = CurPos.QuadPart;
     pStream->Seek(Pos, STREAM_SEEK_SET, NULL);

     // Tworzymy bufor przejsciowy dla strumienia
     void* data = new char[SizeOfFile.QuadPart];
     pStream->Read(data, SizeOfFile.QuadPart, NULL);

     // Przepisujemy dane do TMemoryStream
     TMemoryStream *mStream = new TMemoryStream;
     mStream->Write(data, SizeOfFile.QuadPart);

     // Zapis do pliku
     mStream->SaveToFile("a.jpg");

     delete [] data;

Pozdrawiam!
Ostatnio edytowano piątek, 16 stycznia 2009, 00:16 przez kinio, łącznie edytowano 1 raz
If a machine is expected to be infallible, it cannot also be intelligent.
-- A.Turing
Avatar użytkownika
kinio
Homos antropiczny
Homos antropiczny
 
Posty: 67
Dołączył(a): poniedziałek, 14 lipca 2008, 08:51
Podziękował : 0
Otrzymał podziękowań: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez Witold » czwartek, 15 stycznia 2009, 23:52

Cyfrowy Baron napisał(a):W przytoczonym przez ciebie linku nie ma nic o TMemoryStream ani TStream

jest klasa pochodna: Type TInterfaceStream = Class ( TMemoryStream )

zresztą chodziło mi o sam przykład wykorzystania TOLEStream'a (znalazłem tylko w Delphi, pisałem na podstawie tego i śmigało.)
Avatar użytkownika
Witold
Konstrukcjonista
Konstrukcjonista
 
Posty: 223
Dołączył(a): piątek, 29 sierpnia 2008, 10:53
Podziękował : 1
Otrzymał podziękowań: 14
Kompilator: bcb6, Turbo C++ Explorer
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez Cyfrowy Baron » sobota, 17 stycznia 2009, 13:33

Pomysł kinio w zupełności mi odpowiada. Nie miałem czasu się tym zając, więc takie gotowe rozwiązanie jest jak znalazł. Próbowałem czegoś podobnego ze zmienną char jako buforem, ale ograniczała mnie jej pojemność. Trochę liczyłem, że o czymś nie wiem i istnieje jakaś prosta funkcja, ale tak jest dobrze.
Przedstawiony kod chciałem wykorzystać, nie do zapisywania plików pobranych z sieci d pliku na dysku, lecz do wczytywania bezpośrednio z sieci do obiektu Image, dlatego nieco zmodyfikowałem kod kinio:

Kod: Zaznacz cały
// dołączamy do projektu bibliotekę urlmon.lib
//---------------------------------------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
AnsiString Url ="http://cyfbar.republika.pl/images/img1.jpg";

     IStream* pStream;

     URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, 0);

    LARGE_INTEGER liZero = { 0 };     
    ULARGE_INTEGER CurPos;

     pStream->Seek(liZero, STREAM_SEEK_CUR, &CurPos);

     ULARGE_INTEGER SizeOfFile;
     pStream->Seek(liZero, STREAM_SEEK_END, &SizeOfFile);

     LARGE_INTEGER Pos;
     Pos.QuadPart = CurPos.QuadPart;
     pStream->Seek(Pos, STREAM_SEEK_SET, NULL);

    void* data = new char[SizeOfFile.QuadPart];
    pStream->Read(data, SizeOfFile.QuadPart, NULL);


    std::auto_ptr<TMemoryStream>mStream(new TMemoryStream);
    mStream->Write(data, SizeOfFile.QuadPart);
    mStream->Position = 0;

     String ext = ExtractFileExt(Url);

    if(ext.LowerCase() == ".jpg")
    {
     std::auto_ptr<TJPEGImage> JImage(new TJPEGImage());
     JImage->LoadFromStream(mStream.get());
     Image1->Picture->Assign(JImage.get());
    }
    if(ext.LowerCase() == ".bmp")
    {
          std::auto_ptr<Graphics::TBitmap> Bmp(new Graphics::TBitmap());
     Bmp->LoadFromStream(mStream.get());
     Image1->Picture->Assign(Bmp.get());
       }

    delete [] data;
}
//---------------------------------------------------------------------------


umknęła mi przedstawiona możliwość: void* data = new char i próbowałem podobnie ala zamiast typu void używałem bezpośrednio char o zdefiniowanej wielkości maksymalna dopuszczalna 999999.



Jeżeli chodzi o ściąganie plików na dysk to istnieje prostszy sposób:

Kod: Zaznacz cały
//---------------------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender)
{
  AnsiString Url ="http://cyfbar.republika.pl/images/img3.jpg";
URLDownloadToFile(0, Url.c_str(), "c:\\img3.jpg", 0, 0);
}
//---------------------------------------------------------------------------
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez Witold » niedziela, 18 stycznia 2009, 19:30

Coś podobnego z TOleStream:
Kod: Zaznacz cały
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    AnsiString Url ="http://cyfbar.republika.pl/images/img1.jpg";
    IStream* pStream = 0;

    if (S_OK == URLOpenBlockingStream(0, Url.c_str(), &pStream, 0, 0))
    {
        std::auto_ptr<TOleStream> Adapt(new TOleStream(pStream));
        String ext = ExtractFileExt(Url);

        if (ext.LowerCase() == ".jpg")
        {
            std::auto_ptr<TJPEGImage> JImage(new TJPEGImage());
            JImage->LoadFromStream(Adapt.get());
            Image1->Picture->Assign(JImage.get());
        }
        if  (pStream) pStream->Release();
    }
}


1. Wydaje mi się że pStream->Release() jest potrzebne, może ktoś potwierdzić?
2. To jest legalne w C++ (new char[], delete [] void* ) ?
Kod: Zaznacz cały
  void* data = new char[SizeOfFile.QuadPart];
   delete [] data;
Avatar użytkownika
Witold
Konstrukcjonista
Konstrukcjonista
 
Posty: 223
Dołączył(a): piątek, 29 sierpnia 2008, 10:53
Podziękował : 1
Otrzymał podziękowań: 14
Kompilator: bcb6, Turbo C++ Explorer
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez polymorphism » niedziela, 18 stycznia 2009, 19:53

1. Wydaje mi się że pStream->Release() jest potrzebne, może ktoś potwierdzić?

Potwierdzam.

2. To jest legalne w C++ (new char[], delete [] void* ) ?

Dla purystów językowych nie jest. Akurat w tym konkretnym przypadku nie ma wielkiego problemu, wszak są to typy proste, które nie wymagają specyficznej dekonstrukcji. Ale jeśli mielibyśmy do czynienia z obiektami jakiejś klasy, byłby to poważny błąd. Należy unikać takich praktyk, coby nie nabrać złych nawyków.

PS. W C++ do takich zastosowań, czyli tymczasowych buforów, jest klasa vector.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez banita » niedziela, 18 stycznia 2009, 23:00

zauwaz ze tutaj ten przejsciowy bufor jest modyfikowany w stylu API C, do funkcji podaje sie wskaznik na pierwszy element.
w przypadku vectora i interfejsu API C mozemy zastosowac jedynie funkcje do odczytu ktore nie zmodyfikuja vectora(inaczej vector sie pogubi bo zmiany nastapia bez wykozystania jego interfejsu), przekazujac im adres pierwszego elementu vectora.
zakladajac ze vector jest zaimplementowany w taki sposob ze pracuje na ciaglym obszarze pamieci to przed przekazaniem go do interfejsu API C musimy zarazerwowac odpowiednia ilosc pamieci dla niego (juz nie mamy uroku samo powieksznia sie), dodatkowo musimy funkcja resize zwiekszyc vector o te wpisane elementy aby moc je odczytac.
Avatar użytkownika
banita
Kreacjusz
Kreacjusz
 
Posty: 283
Dołączył(a): poniedziałek, 28 lipca 2008, 20:07
Podziękował : 1
Otrzymał podziękowań: 18
System operacyjny: Windows 7 Professional
Kompilator: C++Builder 2010 Update 5,
Delphi 2010 Update 5,
NetBeans 6.9(MinGw + Qt),
Visual Studio 2008 + Qt
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez polymorphism » niedziela, 18 stycznia 2009, 23:44

zakladajac ze vector jest zaimplementowany w taki sposob ze pracuje na ciaglym obszarze pamieci

Nie zakładamy, to jest w specyfikacji vectora. Zakładać możesz w stringu, bo tu nie ma wymogu ciągłości pamięci.

API C musimy zarazerwowac odpowiednia ilosc pamieci dla niego (juz nie mamy uroku samo powieksznia sie), dodatkowo musimy funkcja resize zwiekszyc vector o te wpisane elementy aby moc je odczytac.

No ale w czym jest problem? Co się stanie jeśli to:
Kod: Zaznacz cały
void* data = new char[SizeOfFile.QuadPart];
pStream->Read(data, SizeOfFile.QuadPart, NULL);

zamienię na:
Kod: Zaznacz cały
vector<char> data(SizeOfFile.QuadPart);
pStream->Read(&data.front(), data.size(), NULL);

:?:



PS. Interface'y COM to API typowe raczej dla C++.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez banita » niedziela, 18 stycznia 2009, 23:49

nic sie nie stanie tylko ze wtedy vector staje sie zwykla ograniczona tablica plus dodatkowa tu niepotzrebna nadbudowa.
do funkcji o strukturze API C powinno sie przekazywac tablice chyba ze akurat mamy kontener STL to wtedy nalezy kontener -> vector -> API C badz bezposrednio vector -> API C.

po co twozyc duzy obiekt (jakim jest vector w porownaniu z tablicami) i swiadomie obcinac jego mozliwosci do zwyklej tablicy o rozmiarze ktory ustala sie raz(tu nie ma balansu rozmiaru).
Avatar użytkownika
banita
Kreacjusz
Kreacjusz
 
Posty: 283
Dołączył(a): poniedziałek, 28 lipca 2008, 20:07
Podziękował : 1
Otrzymał podziękowań: 18
System operacyjny: Windows 7 Professional
Kompilator: C++Builder 2010 Update 5,
Delphi 2010 Update 5,
NetBeans 6.9(MinGw + Qt),
Visual Studio 2008 + Qt
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez polymorphism » poniedziałek, 19 stycznia 2009, 00:33

tylko ze wtedy vector staje sie zwykla ograniczona tablica plus dodatkowa tu niepotzrebna nadbudowa.

No nie taka zwykła i ograniczona - funkcjonalność pozostaje ta sama. No i sama się usunie. Same korzyści :P

po co twozyc duzy obiekt (jakim jest vector w porownaniu z tablicami)

Jak duży? 10, 20 bajtów? Co jak co, ale tym bym się nie przejmował, zważywszy że mowa o VCL'u napisanym w Delphi i stylu programowania w VCL jaki często widuję.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    NieznanyNieznana

Re: Jak przepisać zawartość obiektu typu IStrem do TMemoryStream

Nowy postprzez Witold » poniedziałek, 19 stycznia 2009, 00:38

banita napisał(a):po co twozyc duzy obiekt (jakim jest vector w porownaniu z tablicami) i swiadomie obcinac jego mozliwosci do zwyklej tablicy o rozmiarze ktory ustala sie raz(tu nie ma balansu rozmiaru).

całe ogromniaste 24 bajty (bcb6) lub 32 bajty (bcb2009). Co to jest balast rozmiaru ? Poza tym w std c++ nie ma auto_ptr dla tablic, gdy potrzeba bezpiecznego "auto-zwalniania" pozostaje vector (można też skorzystać z bogactwa boost'a).

Polymorphism, dzięki za potwierdzenie w sprawie pStream->Release().
Avatar użytkownika
Witold
Konstrukcjonista
Konstrukcjonista
 
Posty: 223
Dołączył(a): piątek, 29 sierpnia 2008, 10:53
Podziękował : 1
Otrzymał podziękowań: 14
Kompilator: bcb6, Turbo C++ Explorer
    NieznanyNieznana


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Aplikacje sieciowe

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 16 gości

cron