Delphi TQuery сохранить в CSV-файл

Я хочу экспортировать содержимое TQuery в файл CSV без использования компонента 3D-детали (Delphi 7). Насколько мне известно, это невозможно сделать с помощью стандартных компонентов Delphi.

Моим решением было сохранить контент в StringList в формате CSV и сохранить его в файл.

Есть ли удобное решение?

PS: я не хочу использовать JvCsvDataSet или любой другой компонент. Вопрос в том, может ли это быть достигнуто только с помощью Delphi 7 или более высоких стандартных компонентов?

Заранее спасибо!

5 ответов

Решение

Конечно может.

Вам просто нужно выполнить работу для правильного вывода содержимого 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, но с некоторыми улучшениями: заголовок, escape-символы, вложение только при необходимости и ";" разделитель. Вы можете легко отключить это улучшение, если не требуется.

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

Извините, что отвечаю на вопрос семилетней давности, но если кто-то наткнется на него (как я) и не захочет реализовывать и поддерживать свой собственный модуль записи CSV, следующий код демонстрирует, как использовать компоненты FireDAC (которые устанавливаются вместе с Delphi с тех пор, как XE5), чтобы сохранить набор данных в CSV всего за несколько основных шагов:

      uses
  FireDAC.Comp.BatchMove,
  FireDAC.Comp.BatchMove.Text,
  FireDAC.Comp.BatchMove.DataSet;

procedure SaveDatasetToCSV(IncludeFieldNames : Boolean; Dataset : TDataset; Filename : String);
var
  TextWriter : TFDBatchMoveTextWriter;
  DataSetReader : TFDBatchMoveDataSetReader;
  BatchMove : TFDBatchMove;
begin
  BatchMove := nil;
  try
    BatchMove := TFDBatchMove.Create(nil); 
    TextWriter := TFDBatchMoveTextWriter.Create(BatchMove); 
    DataSetReader := TFDBatchMoveDataSetReader.Create(BatchMove); 

    DataSetReader.DataSet := Dataset;

    TextWriter.FileName := Filename;
    TextWriter.DataDef.WithFieldNames := IncludeFieldNames;

    BatchMove.Reader := DataSetReader;
    BatchMove.Writer := TextWriter; 
    BatchMove.Options := BatchMove.Options + [poClearDest]; //Overrides file if it already exists
    BatchMove.Execute;
  finally
    BatchMove.Free;
  end;
end;
Другие вопросы по тегам