2011-04-15 110 views
10

Quiero exportar el contenido de un TQuery a un archivo CSV sin utilizar un componente de parte 3d (Delphi 7). Por lo que sé, esto no se puede lograr con los componentes estándar de Delphi.Delphi TQuery guardar en el archivo csv

Mi solución fue guardar el contenido en una StringList con formato CSV y guardarlo en un archivo.

¿Hay alguna solución cómoda?

PD: No quiero usar JvCsvDataSet ni ningún componente. La pregunta es: ¿se puede lograr esto solo con los componentes estándar Delphi 7 o superiores?

¡Gracias de antemano!

+4

Es bastante simple escribir un emisor de archivos CSV. Dado que no puede encontrar la funcionalidad integrada, y dado que no desea soluciones de terceros, entonces es probable que deba seguir esta ruta. –

+0

ya que estamos hablando de CSV hay un buen artículo sobre patrones de diseño el uso de un analizador CSV como ejemplo- http://conferences.embarcadero.com/article/32129 – Najem

Respuesta

12

Por supuesto que sí.

Simplemente tiene que hacer el trabajo para generar correctamente el contenido CSV (cotizando correctamente, manejando comillas y comas incrustadas, etc.). Puede escribir fácilmente la salida usando TFileStream, y obtener los datos usando TQuery.Fields y TQuery.FieldCount correctamente.

Dejaré las citas de lujo de CSV y el manejo especial para usted. Esto se hará cargo de la parte fácil:

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; 
+3

Información sobre cómo escapar de sTemp: http: // www.csvreader.com/csv_format.php – jachguate

+0

@Radu Barbu: tenga en cuenta el formato de fecha al importar un csv en una hoja de cálculo (supongo que quiere hacer esto). F.i. Excel intenta adivinar la fecha basándose en la entrada, así que asegúrese de que las fechas se manejen correctamente (si están presentes, por supuesto). Intente convertirlos explícitamente al formato 'dd-mmm-aaaa' si tiene problemas. – Edelcom

9

La pregunta original pedido una solución con un StringList. Entonces sería algo más como esto. Funcionará con cualquier TDataSet, no solo con 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; 

Puede agregar opciones para cambiar el tipo de delimitador o lo que sea.

+0

La pregunta no * pidió * una solución usando TStringList. Solo solicitó una solución que no usara bibliotecas de terceros. –

+0

Solución: requiere punto y coma después de TDataSet, no de coma. "procedimiento WriteDataSetToCSV (DataSet: TDataSet; FileName: String);" –

1

Delphi no proporciona ningún acceso incorporado a los datos .csv. Sin embargo, siguiendo el paradigma VCL TXMLTransform, escribí un helper TCsvTransform que traducirá una estructura .csv a/desde un TClientDataSet. En cuanto a la pregunta inicial que era exportar un TQuery a .csv, un simple TDataSetProvider creará el enlace entre TQuery y TClientDataSet. Para obtener más información sobre TCsvTransform, consulte http://didier.cabale.free.fr/delphi.htm#uCsvTransform

1

Esto es como la solución de Rob McDonell pero con algunas mejoras: encabezado, caracteres de escape, carcasa solo cuando es necesario y ";" separador. Puede deshabilitar fácilmente estas mejoras si no es necesario.

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; 
Cuestiones relacionadas