Zapis/odczyt obiektu klasy do/z pliku binarnego-dziwny blad!

Odpowiedz Nowy wątek
2011-08-30 21:22
0

Witam, tym razem nawet google mi nie pomogły, ani artykuł na tym forum : Odczyt i zapis plików binarnych w Cpp

Hmm to moze zaczne od ukazania mojej klasy:

class c_user
{
    public:
        c_user(std::string i_nick, std::string i_e_mail, std::string i_haslo, std::string i_smtp, short int i_port):
               nick(i_nick), e_mail(i_e_mail), haslo(i_haslo), smtp(i_smtp), port(i_port)
        {
        }
        c_user()
        {
        }
        ~c_user()
        {
        }
 
        std::string GetNick() const {return nick;}
        std::string GetE_mail() const {return e_mail;}
        std::string GetHaslo() const {return haslo;}
        std::string GetSmtp() const {return smtp;}
        short int GetPort() const {return port;}
 
        void SetNick(std::string a_nick) {nick=a_nick;}
        void SetE_mail(std::string a_e_mail) {e_mail=a_e_mail;}
        void SetHaslo(std::string a_haslo) {haslo=a_haslo;}
        void SetSmtp(std::string a_smtp) {smtp=a_smtp;}
        void SetPort(short int a_port) {port=a_port;}
 
    private:
 
        std::string nick;
        std::string e_mail;
        std::string haslo;
        std::string smtp;
        short int port;
};
 

Tworze do niej wskaznik i alokuje pamiec na stercie:

 c_user* pUser=new c_user

W zaleznosci od tego czy uzytkownik wybierze opcje nowej konfiguracji czy uzycia ostatniej konfiguracji wywoluje funkcje: zapis_ostatniej_konfiguracji() ktora zapisuje nowa konfiguracje lub odczut_konfiguracji() gdy uzytkownik wybierze ostatnia konfiguracje..
Zapisuje tak:

pUser=Kreator();//tworzy nowy obiekt typu c_user na stercie
        std::ofstream fout("c_user",std::ios::binary);
        if (!fout) f_error_savefile();
        fout.write((char*) pUser,sizeof (*pUser));
        fout.close(); 

odczytuje tak:

 pUser=new c_user;
            std::ifstream fin("c_user",std::ios::binary);
            if (!fin) f_error_loadfile();
            fin.read((char*) pUser, sizeof (*pUser));
            fin.close();

I niby wszystko okej a jednak w sytuacji kiedy uzytkownik wybierze ostatnia konfiguracje program wywala sie w miejscu gdzie probuje odwolac sie do skladowych klasy c_user.. Wywala sie to znaczy zamiast wypisywac prawidlowe dane to wali jakies nazwy procesow,, katalogi do plikow i ine nie znane mi znaki.. wiec przypuszczam ze cos nie tak jest z zapisem/odczytem do/z plikow bunarnych.. meczylem sie z tym pol dnia i nie wiem co robie zle;( z gory dziekuje za pomoc

Pozostało 580 znaków

2011-08-30 21:26
Rev
0

Nie możesz tak na pałę std::stringów serializować, mają w sobie wskaźniki i inne bajery, które OOTB nie będą się poprawnie zapisywać.

Plik Binarny


edytowany 1x, ostatnio: Rev, 2011-08-30 21:26
Pokaż pozostałe 2 komentarze
Hmm poczytam.. a zamienienie std::stringow na tablice charow cos zmieni?? - mto9 2011-08-30 22:36
Na tablicę charów - tak, ale bez wskaźników oraz czegokolwiek, co w sobie ma wskaźniki. - Rev 2011-08-30 22:49
Ale nazwa tablicy charów to wskaznik do jej pierwszego elementu wiec mimo to zapis i odczyt bedzie ok? Wole sie upewnic przed modyfikacja polowy kodu;/ - mto9 2011-08-30 22:57
Tak, chodzi o to, żeby sizeof(struktura) było poprawne przy zapisie i odczycie. - Rev 2011-08-30 23:00
okej biore sie za poprawe kodu ;) dam znac czy wszystko jest ok;) - mto9 2011-08-30 23:03

Pozostało 580 znaków

2011-08-31 13:43
0

Kombinowalem wczoraj cala noc i nie stety nic nie wymyśliłem :( a modyfikacja kodu na tablice charów była tak żmudna i nie przyjemna że zrezygnowałem... Wstaje rano i jakoś dziwnym trafem dostałem olśnienia :D napisałem sobie dwie funkcje do zapisu / odczytu i wszystko gra tak jak powinno;) Szczególnie dziekuje za wskazówkę że sizeof(struktura) musi być poprawne przy zapisie i odczycie ;) o to te funkcje(może nie najszybsze ale dzialaja tak jak powinny;)) :
Zapis:

void c_user::Zapisz() const
{
    std::ofstream fout("c_user",std::ios::binary);
    if (!fout) f_error_savefile();
 
    char * wpis;
    int waga=nick.length()+1;
    wpis=new char [waga];
    strcpy (wpis, nick.c_str ());
 
    fout.write((char*) & waga,sizeof(waga));
    fout.write(wpis ,waga);
 
    delete [] wpis;
    waga=e_mail.length()+1;
    wpis=new char[waga];
    strcpy (wpis, e_mail.c_str());
 
    fout.write((char*)&waga,sizeof(waga));
    fout.write(wpis ,waga);
 
    delete [] wpis;
    waga=haslo.length()+1;
    wpis=new char[waga];
    strcpy(wpis,haslo.c_str());
 
    fout.write((char*)&waga,sizeof(waga));
    fout.write(wpis,waga);
 
    delete [] wpis;
    waga=smtp.length()+1;
    wpis=new char[waga];
    strcpy(wpis,smtp.c_str());
 
    fout.write((char*)&waga,sizeof(waga));
    fout.write(wpis,waga);
 
    delete [] wpis;
    wpis=0;
 
    fout.write((char*) &port,sizeof (port));
 
    fout.close();
}

Odczyt:

 
void c_user::Wczytaj()
{
    std::ifstream fin("c_user",std::ios::binary);
    if (!fin) f_error_loadfile();
 
    char * wczyt;
    int waga;
 
    fin.read((char*) &waga,sizeof(waga));
    wczyt=new char[waga];
    fin.read(wczyt, waga);
    nick=wczyt;
    delete [] wczyt;
 
    fin.read((char*)&waga,sizeof(waga));
    wczyt=new char[waga];
    fin.read(wczyt,waga);
    e_mail=wczyt;
    delete [] wczyt;
 
    fin.read((char*)&waga,sizeof(waga));
    wczyt=new char[waga];
    fin.read(wczyt,waga);
    haslo=wczyt;
    delete [] wczyt;
 
    fin.read((char*)&waga,sizeof(waga));
    wczyt=new char[waga];
    fin.read(wczyt,waga);
    smtp=wczyt;
    delete [] wczyt;
 
    fin.read((char*) &port,sizeof (port));
 
    fin.close();
}

Pozostało 580 znaków

2011-08-31 13:58
Rev

Wczytując zwykłe prymitywy nie musisz zapisywać ich wielkości, bo ją znasz. Do char* tylko trzeba. No, ale w gruncie rzeczy wiesz już o co chodzi. Możesz sobie wykorzystać tą moją malutką klasę:

#include <iostream>
 
using namespace std;
 
class Utils
{
public:
        template <typename T>
        inline static T Read(istream& stream)
        {
                T value;
                stream.read(reinterpret_cast<char*>(&value), sizeof(value));
 
                return value;
        }
 
        template <typename T>
        inline static void Write(ostream& stream, T value)
        {
                stream.write(reinterpret_cast<char*>(&value), sizeof(value));
        }
 
        template <>
        inline static string Read<string>(istream& stream)
        {
                int length = Read<int>(stream);
                char* value = new char[length + 1];
                stream.read(value, length);
                value[length] = '\0';
                string result = value;
                delete[] value;
 
                return result;
        }
 
        template <>
        inline static void Write<string>(ostream& stream, string value)
        {
                int length = value.length();
                Write(stream, length);
                stream.write(value.c_str(), length);
        }
};

Nie będziesz musiał tyle kodu pisać, a tylko np. Write(plik, zmienna) czy zmienna = Read<int>(plik). A jeszcze lepiej jak w klasie stworzysz dwie metody (jedna statyczna/konstruktor na stworzenie obiektu i druga metoda na wczytanie, które mogą jako argument brać ostream& i istream&. Wtedy całą swoją klasę zapiszesz jednym poleceniem, nawet jak będą w niej jakieś wskaźniki na inne, które też trzeba będzie zapisać.
Przeczytaj tego mojego posta, którego ci wcześniej zalinkowałem z resztą i popatrz na kod.


Pozostało 580 znaków

2011-08-31 14:16
0

Pewnie ta twoja klasa jest o niebo lepsza, ale ja jestem poczatkujacym programista.. nie znam jeszcze szblonow, operacji na strumieniach(moze te podstawowe) , wektorow ani tym podobne ;) dlatego powiem szczerze póki co nie rozumiem tej twojej klasy a już taki jestem że nie lubię używać czegoś czego nie wiem jak działa ;D na razie radze sobie na moj sposób wykorzystując swoja wiedzę.. No ale gdyby nie twoje wskazówki nie napisałbym tych funkcji więc bardzo dziękuje;)

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0