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

#delphi #csv #tquery

#delphi #csv #tquery

Вопрос:

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

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

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

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

Заранее благодарю вас!

Комментарии:

1. Довольно просто написать отправитель файла CSV. Поскольку вы не можете найти встроенную функциональность и поскольку вам не нужны сторонние решения, то вам, вероятно, придется пойти по этому пути.

2. поскольку мы говорим о CSV, есть хорошая статья о шаблонах проектирования, использующих синтаксический анализатор CSV в качестве примера — conferences.embarcadero.com/article/32129

Ответ №1:

Конечно, это возможно.

Вам просто нужно выполнить работу по правильному выводу содержимого CSV (правильное цитирование, обработка встроенных кавычек и запятых и т.д.). Вы можете легко записать выходные данные, используя TFileStream , и получить данные, правильно используя TQuery.Fields и TQuery.FieldCount .

Я оставлю вам причудливое цитирование CSV и специальную обработку. Это позаботится о самой простой части:

 var
  Stream: TFileStream;
  i: Integer;
  OutLine: string;
  sTemp: string;
begin
  Stream := TFileStream.Create('C:DataYourFile.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;
  

Комментарии:

1. Некоторая информация о том, как избежать sTemp: csvreader.com/csv_format.php

2. @Radu Barbu: помните о форматировании даты при импорте csv в электронную таблицу (я предполагаю, что вы хотите это сделать). F.i. Excel пытается угадать дату на основе входных данных, поэтому, пожалуйста, убедитесь, что ваши даты обрабатываются правильно (если они присутствуют, конечно). Попробуйте явно преобразовать их в формат ‘дд-ммм-гггг’, если у вас возникнут проблемы.

Ответ №2:

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

Вы можете добавить параметры для изменения типа разделителя или чего-либо еще.

Комментарии:

1. Вопрос не запрашивал решение с использованием TStringList. Он просто попросил решение, которое не использовало сторонние библиотеки.

2. Исправлено: после TDataSet требуется точка с запятой, а не запятая. «процедура WriteDataSetToCSV(набор данных: TDataSet; имя файла: Строка);»

Ответ №3:

Это похоже на решение Роба Макдонелла, но с некоторыми улучшениями: заголовок, управляющие символы, вложение только при необходимости и разделитель «;». Вы можете легко отключить это улучшение, если оно не требуется.

 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;
  

Ответ №4:

Delphi не предоставляет никакого встроенного доступа к данным .csv. Однако, следуя парадигме VCL TXMLTransform, я написал вспомогательный класс TCsvTransform, который будет преобразовывать структуру .csv в / из TClientDataSet. Что касается первоначального вопроса, который заключался в экспорте TQuery в .csv, простой TDataSetProvider установит связь между TQuery и TClientDataSet. Для получения более подробной информации о TCsvTransform см.http://didier.cabale.free.fr/delphi.htm#uCsvTransform

Ответ №5:

Извините, что отвечаю на вопрос семилетней давности, но если кто-нибудь наткнется на него (как это сделал я) и не захочет внедрять и поддерживать свой собственный CSV writer, следующий код демонстрирует, как использовать компоненты 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;