【问题标题】:Delphi TQuery save to csv fileDelphi TQuery 保存到 csv 文件
【发布时间】:2011-08-06 12:08:15
【问题描述】:

我想在不使用 3d 部件组件(Delphi 7)的情况下将 TQuery 的内容导出到 CSV 文件。据我所知,这不能用 Delphi 标准组件来完成。

我的解决方案是将内容保存在 CSV 格式的 StringList 中,并将其保存到文件中。

有什么舒服的解决办法吗?

PS:我不想使用 JvCsvDataSet 或任何组件。问题是:这只能用 Delphi 7 或更高标准的组件来完成吗?

提前谢谢你!

【问题讨论】:

  • 写一个 CSV 文件发射器非常简单。由于您找不到内置功能,并且您不想要第三方解决方案,那么您可能需要走这条路。
  • 既然我们在谈论 CSV,有一篇关于设计模式的好文章,以使用 CSV 解析器为例-conferences.embarcadero.com/article/32129

标签: delphi csv tquery


【解决方案1】:

这类似于 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;

【讨论】:

    【解决方案2】:

    Delphi 不提供对 .csv 数据的任何内置访问。 但是,按照 VCL TXMLTransform 范例,我编写了一个 TCsvTransform 类助手,它将 .csv 结构转换为 / 从 TClientDataSet 转换。 至于最初的问题是将 TQuery 导出到 .csv,一个简单的 TDataSetProvider 将在 TQuery 和 TClientDataSet 之间建立联系。 有关 TCsvTransform 的更多详细信息,请参阅http://didier.cabale.free.fr/delphi.htm#uCsvTransform

    【讨论】:

      【解决方案3】:

      最初的问题要求使用 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;
      

      您可以添加选项来更改分隔符类型或其他任何内容。

      【讨论】:

      • 问题没有询问使用 TStringList 的解决方案。它只是要求一个不使用 3rd 方库的解决方案。
      • 修复:TDataSet 后面需要分号,而不是逗号。 "过程 WriteDataSetToCSV(DataSet: TDataSet; FileName: String);"
      【解决方案4】:

      当然可以。

      您只需完成正确输出 CSV 内容的工作(正确引用、处理嵌入的引号和逗号等)。您可以使用TFileStream 轻松编写输出,并正确使用TQuery.FieldsTQuery.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;
      

      【讨论】:

      • 一些关于如何逃避 sTemp 的信息:csvreader.com/csv_format.php
      • @Radu Barbu:将 csv 导入电子表格时要注意日期格式(我假设您想这样做)。菲Excel 会尝试根据输入来猜测日期,因此请确保正确处理您的日期(当然如果存在)。如果遇到问题,请尝试将它们显式转换为“dd-mmm-yyyy”格式。
      猜你喜欢
      • 2018-03-09
      • 2015-05-08
      • 2017-08-08
      • 2012-12-22
      • 1970-01-01
      • 2022-12-23
      • 1970-01-01
      • 2019-07-28
      • 1970-01-01
      相关资源
      最近更新 更多