Temat: Zapis/odczyt z pliku obiektu ze string'iem
Sposób zapisu &obiekt, sizeof(obiekt) działa TYLKO przy obiektach nie zawierających żadnych pointerów. Ani zawierających obiektów zawierających pointery, itd...
Generalnie nie możesz go stosować jeżeli twój obiekt zawiera inne klasy, których bajtowego layoutu nie znasz. (ja np. nie wiem jak w pamięci leży string, więc w przykładzie użyję czegoś prostszego)
Pomyśl o takim obiekcie:
class CX
{
int iA;
char* lpszB;
int iC;
int iD;
int iE;
}
Jeżeli teraz go zapiszesz w ten sposób, co znajdzie się w lpszB? Adres pamięci gdzie leży twój string, a nie sam string. Teraz po wczycie masz adres który był ważny przy poprzednim uruchomieniu, ale teraz pamięć na którą wskazuje już nie jest twoja.
To co trzeba zrobić, to rozłożyć zapis na części:
write(&x, sizeof(x) );
write(x.lpszB, sizeof(strlen(lpszB)) ;
Koniecznie obejrzyj ten plik w hexedytorze, to od razu zorientujesz się czy czegoś brakuje.
No dobrze, klasa jest zapisana CAŁA, (nawet więcej niż cała, bo zapisaliśmy wartość pointera, która jest zbędna)
Ale jak teraz ją wczytać? Długość tekstu jest znana przy zapisie, ale przy odczycie *trochę* się nie opłaca jechać bajt po bajcie i czekać na '\0'.
Problem zapisu "rozgałęzionych w pamięci" danych jest rozwiązany, ale teraz jest kolejny, problem wczytu-zapisu danych o nieokreślonej długości:
write(&x, sizeof(x) );
int len = sizeof(strlen(lpszB) +1;//jeden bajt więcej na '\0'
write(len, sizeof(len));
write(x.lpszB, len);
Teraz możesz wczytać:
read(&x, sizeof(x));
int len =0;
read(&len, sizeof(len));
x.lpszB = new char(len); //śmieć wczytany do lpszB zostaje zastąpiony ważnym adresem
read(x.lpszB, len);
Ponieważ piszesz w C++, więc najlepiej takie zamieszanie włożyć do publicznej metody Write(*ofstream pFileToWriteTo) a membery zamknąć privatem.
Klasa jak "string" sama powinna mieć już coś takiego. Wtedy każda klasa zapisuje swoje membery proste, jak inty a następnie woła Write memberom-klasom. W ten sposób jednym Write'm pięknie zapisze i wczyta się całe drzewko.
Oczywiście, można użyć gotowej biblioteki i wszystko zadziała bez zrozumienia problemu : )
Jak pisze Daniel, należy używać typów (intów) których wielkość jest zablokowana i niezależna od kompilatora. Czyli nie int, a jakieś predefinowane typu INT32.
Przydaje się również #pragma pack(1), coby obiekty miały naprawdę wielkość taką jak powinne, bez zaokrąglania w górę.
Szymon Kubisiak edytował(a) ten post dnia 19.06.11 o godzinie 11:01