Delphi csv to excel

Skip to content

uses System.Win.ComObj, ExcelXP, ActiveX;

procedure Split(Delimiter: char; Str: string; ListOfStrings: TStrings) ;
begin
  ListOfStrings.Clear;
  ListOfStrings.Delimiter       := Delimiter;
  ListOfStrings.StrictDelimiter := True; // Requires D2006 or newer.
  ListOfStrings.DelimitedText   := Str;
end;

procedure ExportCSVToExcel(CSV: TStringlist; separator: char; DestName: string;
                           TrimAll: boolean; Freeze: boolean; AutoFilter: boolean);
var
  ovExcelApp: OleVariant;
  ovExcelWorkbook: OleVariant;
  ovWS: OleVariant;
  ovCell: OleVariant;
  i, j: int64;
  columns: TStringList;
  str: string;
  extension: string;
const
  xlWorkbookDefault = 51; // required for XLSX - originally from Excel97.pas
  xlAnd = $00000001;      // required for AutoFilter - originally from ExcelXP.pas
begin
  try
    CoInitialize(nil);
    ovExcelApp := CreateOleObject('Excel.Application'); // If Excel isnt installed will raise an exception
    try
      ovExcelWorkbook := ovExcelApp.WorkBooks.Add;
      ovWS := ovExcelWorkbook.Worksheets.Item[1]; // Go to first worksheet
      ovWS.Activate;
      ovWS.Select;

      columns:=TStringList.Create;
      try
        i:=1;
        while i<=csv.Count do
        begin
          columns.Clear;
          str:=csv.Strings[i-1];
          Split(separator, str, columns);

          j:=1;
          while j<=columns.Count do
          begin
            ovCell:=ovWS.cells[i,j];
            ovCell.numberformat:='@'; // Sets cell format as TEXT
            if TrimAll then
            begin
              ovCell.Formula := trim(columns.Strings[j-1]);
            end else
            begin
              ovCell.Formula := columns.Strings[j-1];
            end;
            inc(j);
          end;

          inc(i);
        end;

        //ovWS.Range['A1','A1'].EntireColumn.AutoFit;
        i:=1;
        while i<=columns.Count do
        begin
          ovWS.cells[1,i].ColumnWidth := 40;
          inc(i);
        end;

      finally
        columns.Free;
      end;

      if AutoFilter then // Apply AutoFilter at top row headers
      begin
        ovWS.Cells.AutoFilter(1, EmptyParam, xlAnd, EmptyParam, True); // xlAnd uses ExcelXP
      end;

      if Freeze then // Freeze top row headers
      begin
        ovExcelApp.ActiveSheet.Rows[2].Select; // 2nd row must be selected
        ovExcelApp.ActiveWindow.FreezePanes := True;
      end;

      ovExcelApp.ActiveSheet.Cells[1,1].Select;

      extension:=extractfileext(lowercase(DestName));
      if extension='.xlsx' then ovWS.SaveAs(DestName, xlWorkbookDefault)        // XLSX
                           else ovWS.SaveAs(DestName, 1, '', '', False, False); // XLS

    finally
      ovExcelWorkbook.Close;
      ovWS := Unassigned;
      ovExcelWorkbook := Unassigned;
      ovExcelApp := Unassigned;
      CoUninitialize;
    end;
  except
    on E : Exception do
    begin
      Application.MessageBox(PChar(E.Message),PChar(tr('WARNING')),MB_ICONWARNING);
    end;
  end;
end;

Example software: CSV to XLS Converter

pivogol

21 / 21 / 8

Регистрация: 07.01.2009

Сообщений: 556

1

31.01.2016, 17:09. Показов 3242. Ответов 2

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Подскажите, пожалуйста, как в Excel сохранить открытый csv-файл как xls?
У меня открывается корректно, но сохраняется неправильно, как текстовый, все столбцы в нём получаются в одной ячейке.
Делаю так:

Delphi
1
2
3
4
5
6
7
8
9
FileName1:=pathp+'reportsout.csv';
FileName2:=pathp+'reportsout.xls';
exclplctn1.Connect;
exclplctn1.Workbooks.Open(FileName1,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,0);
WorkBk:=exclplctn1.WorkBooks.Item[exclplctn1.Workbooks.Count];
WorkSheet := WorkBk.WorkSheets.Get_Item(1) as _WorkSheet;
exclplctn1.ActiveWorkbook.SaveAs(FileName2,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,xlNoChanges,EmptyParam,EmptyParam,EmptyParam,EmptyParam,0, LOCALE_USER_DEFAULT);
exclplctn1.Visible[0]:=True;
exclplctn1.Disconnect;



0



2981 / 2169 / 502

Регистрация: 11.09.2009

Сообщений: 8,086

31.01.2016, 17:30

2

Цитата
Сообщение от pivogol
Посмотреть сообщение

открывается корректно, но сохраняется неправильно

То есть в Excel выглядит нормально, правильно «разложенный» по ячейкам?



0



pivogol

21 / 21 / 8

Регистрация: 07.01.2009

Сообщений: 556

31.01.2016, 22:19

 [ТС]

3

Да, открылся csv-файл чётко, разложено по столбцам.
Потом сохраняю программно в xls, открываю xls, а в нём всё в одной ячейке.
При формировании csv-файла использовал разделитель ;

Добавлено через 4 часа 45 минут
Разобрался.
Понятно, что Excel несмотря на указываемое имя *.xls сохраняет документ в том же формате, в котором и открывал: csv. Нужно явно указать в каком формате сохранять.
Как указывать сохраняемый формат у компонента TExcelApplication, поэтому перешёл на OLE, там формат при сохранении указал так:

Delphi
1
Ap.ActiveWorkBook.SaveAs(FileName2,xlExcel9795);



0



I have a large amount of data to insert into an worksheet of an existing Excel workbook. The Excel workbook will have other worksheets containing calculations and a pivot tables. The data may have as many as 60,000 rows and more than 30 columns. This solution must work for both Excel 2003 and Excel 2007.

Using the Excel OLE object is way too slow so we are attempting to load the data from a CSV file. We have come up with a method to load the data by placing the data onto the clipboard and then pasting it into the worksheet. I feel this is a quite a kludge. Is there another way to programmatically load a CSV file into a worksheet? Or perhaps a different solution altogether?


Update: We got slammed with another task before we could fully investigate the answers. We should be able to get back to this in a couple of weeks. I’ll be sure to update again when we get back to this task.

Thanks for all of the answers to date!

asked Mar 18, 2009 at 1:48

mreith's user avatar

mreithmreith

2994 silver badges15 bronze badges

XLSReadWrite is a component that can read and write excel files from Delphi. It’s fast and it has support for Excel 2003 and 2007. You can create new excel files as well as open existing ones and add/modify them.

Also you do not need to have Excel installed to be able to use it.

See http://www.axolot.com/components/xlsrwii20.htm

answered Mar 18, 2009 at 12:34

ajob's user avatar

ajobajob

2271 gold badge4 silver badges9 bronze badges

1

Any chance you can drop the requirement for this to work with Office 2003? I would have recommended the Open XML Format SDK. It lets you bind managed code assemblies to spreadsheet documents that can handle events such as Open or Close, and read and write to cells in the document, among other things. Alternatively, you can use it to manipulate XSLX documents from an application. Quite slick, actually.

Since this won’t work for you, how about writing a macro that pulls in the CSV file when the spreadsheet is loaded?

answered Mar 18, 2009 at 2:03

cdonner's user avatar

cdonnercdonner

36.8k22 gold badges105 silver badges150 bronze badges

1

you can load the csv into listview or usin OLEDB provider to load it on DBGrid, then export it into xls file format using TMxExport component from Max Components:

Max Components

answered Mar 18, 2009 at 2:02

Dels's user avatar

DelsDels

2,3559 gold badges39 silver badges59 bronze badges

1

Have you tried linking the csv file directly into the worksheet.

Go to Data -> Import External Data -> Import Data
change the file type to ‘Text Files’

You can then refresh the worksheet when the csv is update.

NOTE: I have not done this with the volume of data you have indicated, so YMMV

answered Mar 18, 2009 at 2:11

Craig T's user avatar

Craig TCraig T

2,7615 gold badges25 silver badges33 bronze badges

1

Actually there is a way that is quite fast, pretty old tech (nowdays) but is probably the fastest.

It’s ADO or for earlier versions DAO (note not ADO.NET)

You can read a CSV file using ADO and the JET Engine to get the data into a ADO recordset, then an Excel Range Object has a CopyFromRecordSet method that will copy (very fast) from the ADO (or DAO) recordset.

http://msdn.microsoft.com/en-us/library/aa165427(office.10).aspx

answered Mar 18, 2009 at 3:20

Tim Jarvis's user avatar

Tim JarvisTim Jarvis

18.3k9 gold badges54 silver badges91 bronze badges

1

You can try to use Tab Separated Values instead of CSV — than you just paste this into Excel :)

answered Mar 19, 2009 at 11:45

Jk.'s user avatar

Jk.Jk.

4431 gold badge3 silver badges8 bronze badges

2

Find here a modified compilable version of your code which creates valid BIFF2 files; the demo runs with both Lazarus and Delphi. Before running, please update the path of the destination file at the end of the main procedure in memstream.SaveToFile(…).

  1. program project1;

  2. {$IFDEF FPC}

  3. {$mode objfpc}{$H+}

  4. {$ENDIF}

  5. uses

  6.   Classes, SysUtils;

  7. const

  8.   BIFF_EOF = $000A;

  9.   XLS_SHEET = $0010;

  10. //—

  11.   BOF_BIFF2 = $0009;

  12.   BIFF2_SHEETVIEWSETTINGS_WINDOW2 = $003E;

  13.   LABEL_BIFF2 = $0004;

  14.   DIMENSIONS_BIFF2 = $0000;

  15. //—

  16.   BOF_BIFF5 = $0809;

  17.   LABEL_BIFF5 = $0204;

  18.   DIMENSIONS_BIFF5 = $0200;

  19. type

  20.   TmyDynStringArray = array of string;

  21.   TmyDynStringStringArray = array of TmyDynStringArray;

  22. type

  23.   TXLSWriter = class(Tobject)

  24. private

  25. procedure WriteBIFFRecordHeader(ARecordID: Word; ARecordSize: Word);

  26. procedure WriteByte(B: byte);

  27. procedure WriteWord(W: word);

  28. protected

  29. function ConvertToCodePage(AText: String): ansistring;

  30. procedure WriteBOF;

  31. procedure WriteEOF;

  32. procedure WriteDimension;

  33. procedure WriteCodePage;

  34. public

  35.     Version: Byte;

  36.     DataStream: TMemoryStream;

  37.     MaxCols: Word;

  38.     MaxRows: Word;

  39. procedure CellStr(ARow, ACol: Word; const AValue: String);

  40. constructor Create;

  41. destructor Destroy; override;

  42. end;

  43. constructor TXLSWriter.Create;

  44. begin

  45. inherited Create;

  46.   DataStream := TMemoryStream.Create;

  47.   DataStream.Size := 0;

  48.   MaxCols := 256;

  49.   MaxRows := 65535;

  50. end;

  51. destructor TXLSWriter.Destroy;

  52. begin

  53. if DataStream <> nil then

  54.     DataStream.Free;

  55. inherited;

  56. end;

  57. procedure TXLSWriter.WriteBIFFRecordHeader(ARecordID, ARecordSize: word);

  58. begin

  59.   WriteWord(ARecordID);

  60.   WriteWord(ARecordSize);

  61. end;

  62. procedure TXLSWriter.WriteBOF;

  63. begin

  64. (*

  65.     https://www.openoffice.org/sc/excelfileformat.pdf#page=135&zoom=auto,104.9,771.1

  66.     — 5.8 BOF – Beginning of File

  67.   *)

  68.   WriteBIFFRecordHeader(BOF_BIFF2, 4);

  69.   WriteWord(BOF_BIFF2);

  70.   WriteWord(XLS_SHEET);

  71. end;

  72. procedure TXLSWriter.WriteDimension;

  73. begin

  74. (*

  75.     https://www.openoffice.org/sc/excelfileformat.pdf#page=160&zoom=auto,85.6,581.5

  76.     — 5.35 DIMENSIon

  77.   *)

  78.   WriteBIFFRecordHeader(DIMENSIONS_BIFF2, 8);

  79.   WriteWord(0); // min cols

  80.   WriteWord(MaxRows); // max rows

  81.   WriteWord(0); // min rowss

  82.   WriteWord(MaxCols); // max cols

  83. end;

  84. function TXLSWriter.ConvertString(AText: String): ansistring;

  85. begin

  86. {$IFDEF FPC}

  87.   Result := UTF8ToAnsi(AText);

  88. {$ELSE}

  89.   Result := AnsiString(AText);

  90. {$ENDIF}

  91. end;

  92. procedure TXLSWriter.CellStr(ARow, ACol: Word; const AValue: String);

  93. var

  94.   TmpBytesLen: Cardinal;

  95.   TmpSizeOfFieldLen: Byte;

  96.   TmpStrExcel: AnsiString;

  97. begin

  98. (*

  99.   See:

  100.   — https://www.openoffice.org/sc/excelfileformat.pdf

  101.     «2.5.2 Byte Strings (BIFF2-BIFF5)» states all srings are byte strings

  102.    Strings to not have to include #0 terminator per protocol

  103. *)

  104. if AValue = » then

  105.     exit;

  106.   TmpStrExcel := ConvertToCodePage(AValue);  // To do for Delphi: Convert unicodestring to ansistring

  107.   TmpBytesLen := Length(TmpStrExcel);

  108. //—

  109.   TmpSizeOfFieldLen := 1;

  110. if (TmpBytesLen > 255) then

  111. begin

  112.       TmpBytesLen := 255;

  113. end

  114. ;

  115. //—

  116.   WriteBIFFRecordHeader(LABEL_BIFF2, 2 + 2 + 3 + TmpSizeOfFieldLen + TmpBytesLen);

  117. //—

  118.   WriteWord(ARow);

  119.   WriteWord(ACol);

  120. //—

  121.   WriteByte(0);

  122.   WriteByte(0);

  123.   WriteByte(0);

  124. //—

  125.   WriteByte(Byte(TmpBytesLen));

  126. //—

  127.   DataStream.Write(TmpStrExcel[1], TmpBytesLen);

  128. end;

  129. procedure TXLSWriter.WriteByte(B: Byte);

  130. begin

  131.   DataStream.Write(B, 1);

  132. end;

  133. procedure TXLSWriter.WriteWord(W: word);

  134. begin

  135.   DataStream.Write(W, 2);

  136. end;

  137. procedure TXLSWriter.WriteEOF;

  138. begin

  139. (*

  140.   — https://www.openoffice.org/sc/excelfileformat.pdf#page=161&zoom=auto,113.9,540.2

  141.   5.37 — EOF — End of File

  142. *)

  143.   WriteBIFFRecordHeader(BIFF_EOF, 0);

  144. end;

  145. procedure TXLSWriter.WriteCodePage;

  146. var

  147.   W: Word;

  148. begin

  149. (*

  150.   https://www.openoffice.org/sc/excelfileformat.pdf#page=145&zoom=auto,113.9,771.1

  151.   — 5.17 CODEPAGE

  152. *)

  153.   WriteBIFFRecordHeader($0042, 2);  // $0042 = OPCODE CODEPAGE

  154.   W := 1252;

  155.   WriteWord(W);

  156. end;

  157. function BuildXLSFromStrArrs(const AStrArrs: TmyDynStringStringArray): TMemoryStream;

  158. var

  159.   MR: Integer;

  160.   MC: Integer;

  161.   vxR: Integer;

  162.   vxC: Integer;

  163.   vxL: Word;

  164.   vxS: String;

  165.   vXLS: TXLSWriter;

  166. begin

  167.   MR := Length(AStrArrs);

  168. if MR > 0 then

  169.     MC := Length(AStrArrs[0])

  170. else

  171.     MC := 0;

  172. ;

  173. //—

  174. //

  175. //—

  176.   vXLS := TXLSWriter.Create;

  177.   vXLS.MaxRows := MR;

  178.   vXLS.MaxCols := MC;

  179. //—

  180. //

  181. //—

  182.   vXLS.WriteBOF;

  183. //vXLS.WriteCodePage;   // Not absolutely necessary if you use strings of your code page

  184.   vXLS.WriteDimension;

  185. //—

  186. // TODO: Looking a specificaion, I may need to implement a row structure here

  187. // — wp: not absolutely necessary, only if you want to change row heights and add row formats

  188. //—

  189. for vxC := 0 to MC1 do

  190. begin

  191. for vxR := 0 to MR1 do

  192. begin

  193.       vxS := AStrArrs[vxR,vxC];

  194.       vXLS.CellStr(vxR,vxC,vxS)

  195. end;

  196. end;

  197.   vXLS.WriteEOF;

  198.   vXLS.DataStream.Position := 0;

  199.   Result := TMemoryStream.Create;

  200.   Result.CopyFrom(vXLS.DataStream, vXLS.DataStream.Size);

  201.   Result.Position := 0;

  202.   vXLS.Free;

  203. end;

  204. var

  205.   memstream: TMemoryStream;

  206.   AStrArrs: TmyDynStringStringArray;

  207. begin

  208.   SetLength(AStrArrs, 3);

  209.   SetLength(AStrArrs[0], 2);

  210.   SetLength(AStrArrs[1], 2);

  211.   SetLength(AStrArrs[2], 2);

  212.   AStrArrs[0, 0] := ‘ÄÖÜ’;

  213.   AStrArrs[1, 0] := ‘B’;

  214.   AStrArrs[2, 0] := ‘C’;

  215.   AStrArrs[0, 1] := ‘D’;

  216.   AStrArrs[1, 1] := ‘E’;

  217.   AStrArrs[2, 1] := ‘F’;

  218.   memstream := BuildXLSFromStrArrs(AStrArrs);

  219.   memstream.SaveToFile(‘d:test.xls’);

  220.   memstream.Free;

  221. end.

The problem in your code was that you did not write valid BIFF records consisting of a header and data. A BIFF record header consists of the recordID and the size of the following data, you only wrote the recordID. An important detail is also that strings in the BIFF2 file are ansistrings, but Lazarus and Delphi don’t use these strings by default any more. Therefore you must convert the strings to ansistrings -> function ConvertString():ansistring. An explicit CODEPAGE record in not required if you only write characters of your system codepage (which seems to be 1252).

The next time when you post questions I would appreciate if you could provide a compilable small project — this way it would be easier for me to get started. Pack the pas, lfm, lpr, and lpi files of a Lazarus project into a single zip which you can upload here as an attachment (no binary or other compiler-generated files, please).

Введение

CSV-файл
– простейший по организации файл-таблица, который понимает Microsoft
Excel. CSV – Como Separated Value – данные, разделенные запятой. Это обычный
текстовый файл, в котором каждая строка олицетворяет ряд таблицы, а разделение
этого ряда на колонки осуществляется путем разделения значений специальным
разделителем. Обычно роль этого разделителя, судя из названия, играет запятая.
Однако, встречается и другой разделитель – точка с запятой. Даже в Microsoft не
определились, с каким разделителем должен работать
Excel. При сохранении какой-либо таблицы в формате
CSV, в качестве разделителя используется точка с запятой. Но, при открытии
такого файла с помощью Microsoft Excel, нужно быть очень внимательным, так как, не
знаю, шутка это или нет, существует, как Вы знаете два способа открытия файла:

  1. В главном меню программы выбрать пункт «Открыть» из меню «файл».
  2. Найти на жестком диске нужный файл и два раза кликнуть на нем мышкой.

Так вот, при открытии
CSV файла первым способом,
Excel использует точку с
запятой в качестве разделителя, а при открытии вторым способом
Excel использует запятую в
качестве разделителя. Правда в Microsoft Excel XP эта проблема(?) решена, и используется
только точка с запятой, не смотря на название файла.

Работа с CSV файлами в Delphi

Для работы с
CSV-файлами в
Delphi Вам не понадобятся
различные сторонние компоненты. Как я уже говорил,
CSV-файл – это обычный
текстовый файл. Следовательно, для работы с ним мы будем использовать
стандартный тип TextFile определенный в модуле system.

Давайте напишем процедуру для загрузки
CSV файла в таблицу
TStringGrid
. Это стандартный компонент Delphi для работы со строковыми таблицами. Находится он на странице
Additional в палитре компонентов Delphi.

Вот код этой процедуры:

procedure LoadCSVFile (FileName: String; separator: char);
var f: TextFile;
 s1, s2: string;
 i, j: integer;
begin
 i := 0;
 AssignFile (f, FileName);
 Reset(f);
 while not eof(f) do
 begin
 readln (f, s1);
 i := i + 1;
 j := 0;
 while pos(separator, s1)<>0 do
 begin
 s2 := copy(s1,1,pos(separator, s1)-1);
 j := j + 1;
 delete (s1, 1, pos(separator, S1));
 StringGrid1.Cells[j-1, i-1] := s2;
 end;
 if pos (separator, s1)=0 then
 begin
 j := j + 1;
 StringGrid1.Cells[j-1, i-1] := s1;
 end;
 StringGrid1.ColCount := j;
 StringGRid1.RowCount := i+1;
 end;
 CloseFile(f);
end;

Теперь разберем этот код.

procedure LoadCSVFile (FileName: String; separator: char);

Это заголовок нашей процедуры. В качестве
параметров мы передаем ей имя файла и разделитель данных.

 AssignFile (f, FileName);
 Reset(f);

Здесь мы ассоциируем с файловой переменной
f имя файла и открываем его для
чтения.

while not eof(f) do
 begin
 readln (f, s1);

Пока не достигнут конец файла, читаем из него
очередную строку.

Далее нам остается только разделить строку на
много строк, используя в качестве разделителя символ
separator
, и записать
эти строки в таблицу, учитывая то, что нужно увеличить число рядов на 1. Это
делается следующим кодом:

 while pos(separator, s1)<>0 do
 begin
 s2 := copy(s1,1,pos(separator, s1)-1);
 j := j + 1;
 delete (s1, 1, pos(separator, S1));
 StringGrid1.Cells[j-1, i-1] := s2;
 end;
 if pos (separator, s1)=0 then
 begin
 j := j + 1;
 StringGrid1.Cells[j-1, i-1] := s1;
 end;
 StringGrid1.ColCount := j;
 StringGRid1.RowCount := i+1;

Ну вот, пожалуй, и все что я хотел написать.

Понравилась статья? Поделить с друзьями:
  • Deleted data in excel
  • Delphi and работа с шаблоном word
  • Delete не удаляет в excel
  • Delete workbooks in excel
  • Delphi and microsoft word