[delphi]Zapisywanie klasy

0

Witam!

Mam klasę

type
  TPlik=class
    count:integer;
    tablica:array of  string;
  end;

i nie wiem jak ją zapisać. Próbowałem już z BlockWrite i BlockRead, ale nie zadziałało.
Dzięki

0

to może napisz co chcesz uzyskać :>

0

Chcę uzyskać plik, który łatwo będzie można wczytywać i edytować
(coś w rodzaju zewnętrznego pliku zasobów)

0

Nie wiem, czy zdajesz sobie sprawy z kilku rzeczy:

  • odróżniasz rekord od klasy
  • array of jest tablicą dynamiczną, więc zapisanie jej nie ogranicza się do podania adresu zmiennej i rozmiaru
  • string ma rozmiar dynamiczny (w przeciwności do string[n]) więc jej zapisanie też nie jest takie proste, by podać sam adres i rozmiar przez sizeof(zmienna) - trzeba się bardziej narobić.

Jak nie chce Ci się tego pisać ręcznie i dodatkowo, jeśli wskazana przez ciebie funkcjonalność jest jedną całością, polecam klasę TStringList - nie dość, że ma wszystko, co jest potrzebne do zarządzania stringami, to jeszcze ma gotowe funkcje zapisu/odczytu.

0

Nie musi to być klasa, tylko nie wiem które bardziej się nadaje.
A jak tablica będzie typu np TBitmap, albo jakiegoś mojego rekordu?

0

to trzeba ręcznie (w sensie samemu kod wklepać) po kolei każdą komórkę tablicy zapisać do pliku i jeszcze dodatkowo zapisać sobie ile każda komórka zajmuje i/lub gdzie się zaczyna, żeby przy odczycie było wiadomo

na początek sugerował bym zapoznanie się z klasami pochodnymi od TStream (TMemoryStream, TFileStream) oraz z budową klasy TList oraz analizę klas pochodnych od TList (np. TObjectList, TComponentList) - zauważ, że wyglądają one prawie tak samo.

Jak już załapiesz jak to działa to tworzysz najpierw klasę, która będzie przechowywała pojedyńczy obiekt i na bazie tej klasy włąsną klasę TMyList = class(TList). Ma to tą zaletę, że masz od razu kilka metod, min. Add, Delete, Clear, IndexOf, Extract, First, Last, Insert, Move, Remove, Assign itd. Może na pierwszy rzut oka wydaje się to skąplikowane ale po ogarnięciu jest bardzo wygodne i praktyczne

Tu masz przykład z zapisem do listy rekordu

0

Może przykładzik, do klasy zamieszczonej powyżej:

type
  TPlik=class
    Count:integer;
    Tablica:array of string;
  public
    procedure SaveToFile(FileName:TFileName);
    procedure LoadFromFile(FileName:TFileName);
  end;

{ TPlik }

procedure TPlik.LoadFromFile(FileName:TFileName);
var Handle:THandle;
    i:integer;
    len:integer;
    read:DWORD;
begin
Handle:=CreateFile(PChar(FileName), GENERIC_READ, 0, nil, OPEN_ALWAYS, 0, 0);
if (Handle<>INVALID_HANDLE_VALUE) then
  begin
  ReadFile(Handle, Count, sizeof(count), read, nil);
  SetLength(tablica, count);
  for i:=0 to count-1 do
    begin
    ReadFile(Handle, len, sizeof(len), read, nil);
    SetLength(tablica[i], len);
    ReadFile(Handle, PChar(tablica[i])^, len, read, nil);
    end;
  CloseHandle(Handle);
  end;
end;

procedure TPlik.SaveToFile(FileName:TFileName);
var Handle:THandle;
    i:integer;
    len:integer;
    written:DWORD;
begin
Handle:=CreateFile(PChar(FileName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0);
if (Handle<>INVALID_HANDLE_VALUE) then
  begin
  WriteFile(Handle, Count, sizeof(count), written, nil);
  for i:=0 to count-1 do
    begin
    len:=length(tablica[i]);
    WriteFile(Handle, len, sizeof(len), written, nil);
    WriteFile(Handle, PChar(tablica[i])^, len, written, nil);
    end;
  CloseHandle(Handle);
  end;
end;

Ogólna idea jest taka: najpierw zapisujesz ile co zajmuje, a potem dopiero dane tego czegoś. Najpierw ile elementów ma tablica, potem ile ma każdy element, dopiero na końcu dane tego elementu (tutaj stringu). Oczywiście robisz tak tylko w przypadku zmiennych/obiektów, które nie mają stałego rozmiaru.

Przy odczycie na odwrót. Odczytujesz ile elementów ma mieć tablica, alokujesz tablicę, ile ma mieć element poszczególnych stringów, alokujesz stringi, a dopiero na końcu, kiedy masz miejsce na dane, wczytujesz te - tutaj treść stringów.

0

Dzięki Szczawik!
Gdyby tablica była klasy TPicture albo TGraghic?
A tak w ogóle to klasy TObjectList, TComponentList w którym module się znajdują?

0

To musisz ręcznie. Może przykład zapisu klasy z dwoma bitmapami:

  TPlik = class
  public
    bmp1:TBitmap;
    bmp2:TBitmap;
    constructor Create();
    destructor Destroy; override;
    procedure SaveToFile(FileName:TFileName);
    procedure LoadFromFile(FileName:TFileName);
  end;

{ TPlik }

constructor TPlik.Create;
begin
inherited;
bmp1:=TBitmap.Create;
bmp2:=TBitmap.Create;
end;

destructor TPlik.Destroy;
begin
bmp1.Free;
bmp2.Free;
inherited;
end;

procedure TPlik.LoadFromFile(FileName: TFileName);
var Str:TMemoryStream;
    FileStr:TFileStream;
    n:integer;
begin
Str:=TMemoryStream.Create;
FileStr:=TFileStream.Create(FileName, fmOpenRead);

FileStr.ReadBuffer(n, sizeof(n));
Str.CopyFrom(FileStr, n);
Str.Position:=0;
bmp1.LoadFromStream(Str);
Str.Clear;

FileStr.ReadBuffer(n, sizeof(n));
Str.CopyFrom(FileStr, n);
Str.Position:=0;
bmp2.LoadFromStream(Str);

FileStr.Free;
Str.Free;
end;

procedure TPlik.SaveToFile(FileName: TFileName);
var Str:TMemoryStream;
    FileStr:TFileStream;
    n:integer;
begin
Str:=TMemoryStream.Create;
FileStr:=TFileStream.Create(FileName, fmOpenWrite);

bmp1.SaveToStream(Str);
n:=Str.Size;
FileStr.WriteBuffer(n, sizeof(n));
Str.SaveToStream(FileStr);
Str.Clear;

bmp2.SaveToStream(Str);
n:=Str.Size;
FileStr.WriteBuffer(n, sizeof(n));
Str.SaveToStream(FileStr);

FileStr.Free;
Str.Free;
end;

Przykład użycia:

var Plik:TPlik;
begin
Plik:=TPlik.Create;
try
  Plik.bmp1.Assign(Image1.Picture.Bitmap);
  Plik.bmp2.Assign(Image2.Picture.Bitmap);
  Plik.SaveToFile('c:\plik.txt');
  Plik.bmp1.Assign(nil);
  Plik.bmp2.Assign(nil);
  Plik.LoadFromFile('c:\plik.txt');
  Image3.Picture.Bitmap.Assign(Plik.bmp1);
  Image4.Picture.Bitmap.Assign(Plik.bmp2);
except
  end;
Plik.Free;
end;
0

Dzięki!
A byłby jakiś sposób na dynamiczną tablicę typu TBitmap??

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