Einzelnen Beitrag anzeigen

Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#21

Re: FileQuickSort (Dateien mit wenig Speicherlast sortieren)

  Alt 15. Mär 2009, 08:41
Hatte ich erst auch nicht verstanden, bei PrefetchSize = 0 sollte ja der Zeitaufwand gleich sein. Aber ist es nicht. Test-Datei und Sortier-Routine ist ja bis auf die andere Behandlung der Zeilen identisch.

da ich mich aber auch gleichzeitig noch mit der Klasse an sich beschäftigt hatte, ist da möglicherweise noch ein Fehler drin:
Delphi-Quellcode:
{<--- Holt eine Textzeile aus der Quell-Datei --->}
function TTextFileSorter.LineFromFile(Row : Integer): AnsiString;
var
  CharStr : PAnsiChar;
  index : TLineIndex;
begin
  index := FFileIndex[Row];
  CharStr := StrAlloc(Index.size +1);
  FillChar(CharStr^, Index.size +1, #0);
  FInFileStream.Seek(Index.offset, soFromBeginning);
  FInFileStream.Read(CharStr^, Index.size);
  Result := CharStr;
  StrDispose(CharStr);
end;

{<--- Holt eine Textzeile via Index-Werte --->}
function TTextFileSorter.GetIndexLine(Row: Integer; LineTyp: TGetLineTyp): AnsiString;
begin
  case LineTyp of
    glt_File : Result := LineFromFile(Row);
    glt_FileUpper : Result := AnsiUpperCase(LineFromFile(Row));
    glt_Prefetch : Result := FFileIndex[Row].prefetch;
  end;
end;

{<--- Vergleicht Strings genau, also bei Bedarf nachladen --->}
function TTextFileSorter.CompareLinesExact(Row1, Row2 : Integer) : Integer;
begin
  Result := CompareStr(GetIndexLine(Row1, glt_Prefetch),GetIndexLine(Row2, glt_Prefetch));
  // Prefetch gleich, dann aus Quell-Datei vergleichen
  if Result = 0 then
    Result := CompareStr(GetIndexLine(Row1, glt_FileUpper),GetIndexLine(Row2, glt_FileUpper));
end;

{<--- Quicksort des Index mit Nachladen einer Zeile bei Bedarf --->}
procedure TTextFileSorter.SortIndex(LoIndex, HiIndex: Integer);
var
  LoIdx, HiIdx, PivotIdx: Integer;
  Swap : TLineIndex;
  Promille : Integer;
begin
  if FCancelSort then Exit;

  // Lokalen Indexbereich bilden
  LoIdx := LoIndex;
  HiIdx := HiIndex;
  PivotIdx := (LoIndex + HiIndex) div 2;

  repeat
    while CompareLinesExact(LoIdx, PivotIdx) < 0 do Inc(LoIdx);
    while CompareLinesExact(PivotIdx, HiIdx) < 0 do Dec(HiIdx);
    //while GetLine(LoIdx, LineTyp) < Pivot do Inc(LoIdx);
    //while Pivot < GetLine(HiIdx, LineTyp) do Dec(HiIdx);

    if LoIdx <= HiIdx then begin
      if LoIdx < HiIdx then begin
        Swap := FFileIndex[LoIdx];
        FFileIndex[LoIdx] := FFileIndex[HiIdx];
        FFileIndex[HiIdx] := Swap;
      end;
      Inc(LoIdx);
      Dec(HiIdx);
    end;

  until LoIdx > HiIdx;

  // NotifyEvent nur alle 0,1% aufrufen
  if Assigned(FOnSorting) then begin
    Promille := (LoIndex * 1000) div Length(FFileIndex);
    if Promille > FLastPromille then begin
      FLastPromille := Promille;
      FOnSorting(self, tfsSorting , Promille div 10, FCancelSort);
    end;
  end;

  if LoIndex < HiIdx then SortIndex(LoIndex, HiIdx);
  if LoIdx < HiIndex then SortIndex(LoIdx, HiIndex);
end;
Beim Anlegen der Ziel-Datei wird jetzt nur noch Zeile gelesen -> geschrieben

Evtl. könnte man hier
Delphi-Quellcode:
  while CompareLinesExact(LoIdx, PivotIdx) < 0 do Inc(LoIdx);
  while CompareLinesExact(PivotIdx, HiIdx) < 0 do Dec(HiIdx);
Auf Prefetch=0 prüfen und direkt die Dateizeilen (ohne Aufruf von CompareLinesExact) laden.
  Mit Zitat antworten Zitat