我想在不使用 3d 部件组件(Delphi 7)的情况下将 TQuery 的内容导出到 CSV 文件。据我所知,这不能用 Delphi 标准组件来完成。
我的解决方案是将内容保存在 CSV 格式的 StringList 中,并将其保存到文件中。
有什么舒服的解决办法吗?
PS:我不想使用 JvCsvDataSet 或任何组件。问题是:这只能用 Delphi 7 或更高的标准组件来完成吗?
先感谢您!
当然可以。
您只需完成正确输出 CSV 内容的工作(正确引用、处理嵌入的引号和逗号等)。您可以使用 轻松编写输出,并使用和正确TFileStream
获取数据。TQuery.Fields
TQuery.FieldCount
我将把花哨的 CSV 引用和特殊处理留给你。这将处理简单的部分:
var
Stream: TFileStream;
i: Integer;
OutLine: string;
sTemp: string;
begin
Stream := TFileStream.Create('C:\Data\YourFile.csv', fmCreate);
try
while not Query1.Eof do
begin
// You'll need to add your special handling here where OutLine is built
OutLine := '';
for i := 0 to Query.FieldCount - 1 do
begin
sTemp := Query.Fields[i].AsString;
// Special handling to sTemp here
OutLine := OutLine + sTemp + ',';
end;
// Remove final unnecessary ','
SetLength(OutLine, Length(OutLine) - 1);
// Write line to file
Stream.Write(OutLine[1], Length(OutLine) * SizeOf(Char));
// Write line ending
Stream.Write(sLineBreak, Length(sLineBreak));
Query1.Next;
end;
finally
Stream.Free; // Saves the file
end;
end;
最初的问题要求使用 StringList 的解决方案。所以它会更像这样。它适用于任何 TDataSet,而不仅仅是 TQuery。
procedure WriteDataSetToCSV(DataSet: TDataSet, FileName: String);
var
List: TStringList;
S: String;
I: Integer;
begin
List := TStringList.Create;
try
DataSet.First;
while not DataSet.Eof do
begin
S := '';
for I := 0 to DataSet.FieldCount - 1 do
begin
if S > '' then
S := S + ',';
S := S + '"' + DataSet.Fields[I].AsString + '"';
end;
List.Add(S);
DataSet.Next;
end;
finally
List.SaveToFile(FileName);
List.Free;
end;
end;
您可以添加选项来更改分隔符类型或其他任何内容。
这类似于 Rob McDonell 解决方案,但具有一些增强功能:标题、转义字符、仅在需要时进行封装和“;” 分隔器。如果不需要,您可以轻松禁用此增强功能。
procedure SaveToCSV(DataSet: TDataSet; FileName: String);
const
Delimiter: Char = ';'; // In order to be automatically recognized in Microsoft Excel use ";", not ","
Enclosure: Char = '"';
var
List: TStringList;
S: String;
I: Integer;
function EscapeString(s: string): string;
var
i: Integer;
begin
Result := StringReplace(s,Enclosure,Enclosure+Enclosure,[rfReplaceAll]);
if (Pos(Delimiter,s) > 0) OR (Pos(Enclosure,s) > 0) then // Comment this line for enclosure in every fields
Result := Enclosure+Result+Enclosure;
end;
procedure AddHeader;
var
I: Integer;
begin
S := '';
for I := 0 to DataSet.FieldCount - 1 do begin
if S > '' then
S := S + Delimiter;
S := S + EscapeString(DataSet.Fields[I].FieldName);
end;
List.Add(S);
end;
procedure AddRecord;
var
I: Integer;
begin
S := '';
for I := 0 to DataSet.FieldCount - 1 do begin
if S > '' then
S := S + Delimiter;
S := S + EscapeString(DataSet.Fields[I].AsString);
end;
List.Add(S);
end;
begin
List := TStringList.Create;
try
DataSet.DisableControls;
DataSet.First;
AddHeader; // Comment if header not required
while not DataSet.Eof do begin
AddRecord;
DataSet.Next;
end;
finally
List.SaveToFile(FileName);
DataSet.First;
DataSet.EnableControls;
List.Free;
end;
end;
Delphi 不提供对 .csv 数据的任何内置访问。但是,按照 VCL TXMLTransform 范例,我编写了一个 TCsvTransform 类助手,它将 .csv 结构转换为 / 从 TClientDataSet 转换。至于最初的问题是将 TQuery 导出到 .csv,一个简单的 TDataSetProvider 将在 TQuery 和 TClientDataSet 之间建立联系。有关 TCsvTransform 的更多详细信息,请参见http://didier.cabale.free.fr/delphi.htm#uCsvTransform