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
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
to może napisz co chcesz uzyskać :>
Chcę uzyskać plik, który łatwo będzie można wczytywać i edytować
(coś w rodzaju zewnętrznego pliku zasobów)
Nie wiem, czy zdajesz sobie sprawy z kilku rzeczy:
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.
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?
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
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.
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ą?
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;
Dzięki!
A byłby jakiś sposób na dynamiczną tablicę typu TBitmap??