Delphi TQuery сохраняет файл csv

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

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

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

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

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

Ответ 1

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

Вам просто нужно выполнить работу, чтобы правильно выводить содержимое 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;

Ответ 2

В исходном вопросе задано решение с использованием 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;

Вы можете добавить опции для изменения типа разделителя или любого другого.

Ответ 3

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

Ответ 4

Это похоже на решение Роба МакДонелла, но с некоторыми улучшениями: заголовок, 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;