So also hier mal mein Versuch, das in eine Klasse zu packen:
Interface Teil:
Delphi-Quellcode:
uses SysUtils, Classes;
resourcestring
txt_SourceFileError = '
Quell-Datei kann nicht geöffnet werden!';
txt_TargetFileError = '
Ziel-Datei kann nicht geöffnet werden!';
type
EFileSorterOpenError =
class(
Exception);
TLineIndex =
record
offset,
size : Integer;
prefetch : AnsiString;
end;
TFileIndex =
array of TLineIndex;
TTextFileSorterStatus = (tfsIndexing, tfsSorting, tfsWriting, tfsDone);
TGetLineTyp = (glt_File, glt_FileUpper, glt_Prefetch);
TSortNotifyEvent =
procedure (Sender : TObject; Status : TTextFileSorterStatus;
PercentDone : Integer;
var Cancel : Boolean)
of object;
TTextFileSorter =
class
private
FInFileStream : TFileStream;
FLastPromille : Integer;
FCancelSort : Boolean;
FFileIndex : TFileIndex;
FFileIndexBlock : Integer;
FPrefetchSize : Integer;
FSourceFilename:
String;
FDestinationFilename:
String;
FOnSorting: TSortNotifyEvent;
procedure SetPrefetchSize(
const Value : Integer);
procedure SetDestinationFilename(
const Value:
String);
procedure SetOnSorting(
const Value: TSortNotifyEvent);
procedure SetSourceFilename(
const Value:
String);
protected
procedure LoadIndex;
function LineFromFile(Row : Integer): AnsiString;
function GetIndexLine(Row : Integer; LineTyp : TGetLineTyp): AnsiString;
function CompareLinesExact(Row1, Row2 : Integer) : Integer;
procedure SortIndex(LoIndex, HiIndex: Integer);
procedure WriteTargetFile;
public
constructor Create(aSourceFile, aDestFile :
String);
destructor Destroy;
override;
procedure Sort;
property PrefetchSize : Integer
read FPrefetchSize
write SetPrefetchSize;
property SourceFilename :
String read FSourceFilename
write SetSourceFilename;
property DestinationFilename :
String read FDestinationFilename
write SetDestinationFilename;
property OnSorting : TSortNotifyEvent
read FOnSorting
write SetOnSorting;
end;
...und ein Beispiel für die Nutzung:
Delphi-Quellcode:
procedure TFormFileSort.SortNotifyEvent(Sender : TObject; Status : TTextFileSorterStatus;
PercentDone : Integer; var Cancel : Boolean);
resourcestring
txt_StatusIndex = 'Index wird aufgebaut...';
txt_StatusSort = 'Sortiere Datei (%d%%)';
txt_StatusWrite = 'Schreibe Ziel-Datei...';
txt_StatusDone = 'Fertig.';
begin
ProgressBar1.Position := PercentDone;
case Status of
tfsIndexing : GroupBoxWork.Caption := txt_StatusIndex;
tfsSorting : GroupBoxWork.Caption := Format(txt_StatusSort,[PercentDone]);
tfsWriting : GroupBoxWork.Caption := txt_StatusWrite;
tfsDone : GroupBoxWork.Caption := txt_StatusDone;
end;
Application.ProcessMessages;
end;
procedure TFormFileSort.Button1Click(Sender: TObject);
var
TextFileSorter : TTextFileSorter;
begin
TextFileSorter := TTextFileSorter.Create(EditSource.Text,EditTarget.Text);
try
TextFileSorter.OnSorting := SortNotifyEvent;
TextFileSorter.PrefetchSize := SpinEditPrefetch.Value;
TextFileSorter.Sort;
finally
TextFileSorter.Free;
end;
end;
Die komplette
Unit mit der Klasse liegt in der Anlage.
Wahrscheinlich sind noch Anfänger-Fehler drin, da ich mit der Verwendung von Klassen nur wenig bis gar keine Ahnung hab'. Mir sind auch ein paar Fragen gekommen:
Die Verteilung der Variablen und Methoden ist so richtig (private, protected)?
Methoden greifen auf Variablen innerhalb der Klasse zu, damit nicht unabhängig, trotzdem OK?
Class TList (Delphi Source) lagert QuickSort in eine lokale Funktion der
Unit aus, warum?
Eigene Exeption sinnvoll, wenn FileOpen ein Standard-Fehler ist?
***
Es ist wohl sinnvoll es aus der Code-Library raus zu nehmen und passend zu verschieben. Ich ändere den Titel dann in etwa wie folgt um. "Von Standard-Code zu einer Klasse" (<- oder bitte vom verschiebenden Moderator gleich passen zu ändern). Danke!