Eigentlich braucht man dafür nichts fertiges. Aber wenn Zellen leer sind, oder die Spaltentrenner oder Zeilenumbrüche enthalten, ist es doch gut auf das "offizielle" Tool des FPC zurückzugreifen, das CSVDocument. Seitdem dieses in fpc integriert ist, sind die Schreib/Leseroutinen in Unit
csvreadwrite abgespalten und das reicht für diese Aufgabe.
- Also zunächst "uses csvreadwrite".
- Dann eine Instanz von TCSVBuilder erzeugen (csv := TCSVBuilder.Create).
- Spaltentrennzeichen festlegen: csv.Delimiter := #9
- Ausgabestream festlegen: csv.SetOutput(stream), wenn nicht geht die Ausgabe in einem Memorystream (csv.DefaultOutput), den man am Ende in eine Datei schreiben kann.
- Liste Element für Element durchlaufen
- Jedes RecordElement in einen String umwandeln und per csv.AddCell(string) in den Stream schreiben. Bei Gleitkommazahlen schreibe ich immer mit Dezimalpunkt (und lese später auch genauso wieder ein), d.h. FormatSettings entsprechend präparieren (dieser Schritt kann aber entfallen).
- Nach dem letzten Element csv.AddRow für neue Zeile
- Zum nächsten Listenelement
Hier ein lauffähiges Beispiel (nur ein Formular mit einem Button), allerdings nur der Normalfall mit "normalen" Zellen, keine Zeilenumbrüche in der Zelle und sowas (dazu müsste man entsprechende Properties im csvBuilder bzw. dessen Vorfahren TCSVHandler setzen):
Code: Alles auswählen
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
uses
csvreadwrite; // <--- wichtig
{$R *.lfm}
type
TData = record
x: Double;
s: String;
end;
PData = ^TData;
var
list: TList;
function NewDataRecord(x: Double; s: String): PData;
begin
New(Result);
Result^.x := x;
Result^.s := s;
end;
procedure DisposeDataRecord(P: PData);
begin
P^.s := '';
Dispose(P);
end;
procedure CreateDataList(out list: TList);
var
i: Integer;
begin
list := TList.Create;
for i:=1 to 100 do
List.Add(NewDatarecord(Random, 'abcdefg' + IntToStr(i)));
end;
procedure DestroyDataList(list: TList);
var
i: Integer;
begin
for i:=0 to list.Count-1 do
DisposeDataRecord(PData(list[i]));
list.Free;
end;
procedure WriteToCSV(AFilename: String; list: TList); // <--- das ist die CSV-Routine
var
csv: TCSVBuilder;
P: PData;
i: Integer;
fs: TFormatSettings;
begin
fs := DefaultFormatSettings;
fs.DecimalSeparator := '.'; // Dezimalpunkt statt -komma
csv := TCSVBuilder.Create;
try
csv.Delimiter := #9; // Tabulator als Spaltentrenner
// Spaltennamen
csv.AppendCell('x');
csv.AppendCell('s');
csv.AppendRow;
// Wertetabelle
for i:=0 to list.Count-1 do begin
P := PData(list[i]);
csv.AppendCell(FloatToStr(P^.x, fs));
csv.AppendCell(P^.s);
if i < list.Count - 1 then
csv.AppendRow;
end;
csv.DefaultOutput.SaveToFile(AFilename);
finally
csv.Free;
end;
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
list: TList;
begin
CreateDataList(list);
try
WriteToCSV('d:\test.txt', list);
finally
DestroyDataList(list);
end;
end;
end.