Jest jakiś sposób na szybkie zapisanie całej listy w ListView za pomocą BlockWrite a potem je odczytać BlockRead? Itemów może być nawet kilkanaście tysięcy dlatego zależy mi na BlockWrite bo bije inne sposoby na łopatki pod względem prędkości. Tablice rekordów potrafie zapisywać ale z ListView mam problem. Może mi ktoś pomóc?
Jeżeli chodzi o szybkość to najlepiej było by wykorzystać strumienie (TMemoryStream)
Co do zapisu to tekst w strumieniach można zapisywać w taki sposób że najpierw zapisujesz długość tekstu a potem tekst np tak:
var Len: Integer;
mem: TMemoryStream;
st: TStringStream;
s: string;
begin
s := 'tekst';
st := TStringStream.Create(s);
Len := st.Size;
// zapis tekstu
mem := TMemoryStream.Create;
mem.Write(Len, SizeOf(Len));
mem.CopyFrom(st, len);
mem.Free;
st.Free;
end;
To jest bardzo szybkie.
Potem zmienną TMemoryStream można zapisać do pliku za pomocą TFileStream.
Jestem teraz w pracy i nie mam jak sprawdzić ale czy można tą metodą zapisać jakoś całego itema (TListItem) wraz ze strukturą subitemów (mam ich aż 7). Byłbym wdzięczny także za przykład odczytu, jeżeli nie to wyszukam sam ;)
Na początek 2 przydatne rzeczy (zapis i odczyt tekstu w strumieniu):
procedure WriteString(FStream: TStream; StringData: String);
var S: TStringStream;
Len: DWord;
begin
if StringData = '' then begin
Len := 0;
FStream.Write(Len, SizeOf(Len));
end else begin
S := TStringStream.Create(StringData);
try
Len := S.Size;
FStream.Write(Len, SizeOf(Len));
FStream.CopyFrom(S, Len);
finally
S.Free;
end;
end;
end;
function ReadString(FStream: TStream): String;
var S: TStringStream;
Len: DWord;
begin
Result := '';
FStream.Read(Len, SizeOf(DWord));
if Len = 0 then begin
Result := '';
end else begin
S := TStringStream.Create('');
try
S.CopyFrom(FStream, Len);
Result := S.DataString;
finally
S.Free;
end;
end;
end;
A teraz procedury zapisu i odczytu pojedynczego "item'a" w TListView:
procedure SaveItemToStream(Stream: TStream; const itm: TListItem);
var i, sCount: Integer;
begin
// zapis Caption
WriteString(Stream, itm.Caption);
// zapis liczby subitems
sCount := itm.SubItems.Count;
Stream.Write(sCount, SizeOf(sCount));
// zapis subitems
for i:=0 to sCount-1 do begin
WriteString(Stream, itm.Subitems[i]);
end;
end;
procedure LoadItemFromStream(Stream: TStream; var itm: TListItem);
var i, sCount: Integer;
begin
// odczyt Caption
itm.Caption := ReadString(Stream);
// odczyt liczby subitems
Stream.Read(sCount, SizeOf(sCount));
// odczyt subitems
for i:=0 to sCount-1 do begin
itm.SubItems.Add(ReadString(Stream));
end;
end;
Na koniec mały test tego co jest wyżej napisane:
procedure TForm1.Button1Click(Sender: TObject);
var i: Integer;
mem: TMemoryStream;
adedItem: TListItem;
begin
mem := TMemoryStream.Create;
try
// petal odczytująca i zapisująca itemy do i z strumienia
// LV1 to jedno ListView
// LV2 to ListView do którego zapisywane są itemy z LV1
for i:=0 to LV1.Items.Count-1 do begin
// zerowanie strumienia i ustawianie pozycji
mem.Size := 0;
mem.Position := 0;
// zapisywanie Item'a do strumienia
SaveItemToStream(mem, LV1.Items[i]);
// dodawanie nowej pozycji
adedItem := LV2.Items.add;
// ustawianie na początku strumienia
mem.Position := 0;
// odczyt ze strumienia
LoadItemFromStream(mem, adedItem);
end;
finally
mem.Free;
end;
end;
Kod był testowany i działa poprawnie. Pozdrawiam
Dzięki Mike!! Należy ci się wielkie [soczek] . Własnie o to mi chodziło, zwłaszcza o pojedyńcze "wrzucanie" itemów do pliku.
Sorry za przekręcenie nazwiska [glowa] . Mam jeszcze małą prośbę, jak wrzucić tego itema do pliku? Przyznam się bez bicia że unikałem strumieni jak ognia a nie wiem czemu bo teraz widze że to bardzo przydatna rzecz i nie wiele o nich wiem. Mam internet z prędkością GPRS i ciężko idzie mi szukanie artykułu jakiego potrzebuje
Z zapisem do pliku też nie ma dużo roboty. Można to rozwiązać w taki sposób:
procedure SaveItemsToFile(lv: TListView; const aFile: String);
var i, iCount: Integer;
F: TFileStream;
begin
F := TFileStream.Create(aFile, fmCreate);
try
iCount := lv.Items.Count;
F.Write(iCount, SizeOf(iCount));
for i:=0 to iCount-1 do begin
// zapisywanie Item'a do strumienia
SaveItemToStream(F, lv.Items[i]);
end;
finally
F.Free;
end;
end;
Odczyt też nie sprawia problemu:
procedure LoadItemsFromFile(lv: TListView; const aFile: String);
var i, iCount: Integer;
F: TFileStream;
itm: TListItem;
begin
F := TFileStream.Create(aFile, fmOpenRead);
try
F.Read(iCount, SizeOf(iCount));
for i:=0 to iCount-1 do begin
itm := lv.Items.Add;
// odczyt Item'a do strumienia
LoadItemFromStream(F, itm);
end;
finally
F.Free;
end;
end;
Przykład wykorzystania:
procedure TForm1.Button2Click(Sender: TObject);
begin
SaveItemsToFile(LV1, 'plik.txt');
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
LoadItemsFromFile(LV2, 'plik.txt');
end;
Kod działa poprawnie - testowałem u siebie.
W razie pytań pisz na maila to wtedy dostaniesz odpowiedź z przykładowym kodem w Delphi.
Pozdrawiam