[Delphi] ListView i BlockWrite

0

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?

0

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.

0

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 ;)

0

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

0

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.

0

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

0

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

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