Sign in Join
Wiki copytemporary

CsvDocument

English · Русский

About

CsvDocument library is a unit contaning set of classes for CSV files handling. The library was created to exchange data with OpenOffice Calc / MS Office Excel using CSV as intermediate format.

Its main characteristics are:

Author

Vladimir Zhirov

Contributors

Luiz Americo Pereira Camara

Mattias Gaertner

Reinier Olislagers

License

ModifiedLGPL (same as FPC RTL and Lazarus LCL).

Dependencies

The library is a single Pascal source file that only depends on FPC RTL and FCL.

Availability/Download

Since FPC 3.0, CSVDocument belongs to the FCL (folder fcl-base/src, units csvreadwrite.pp and csvdocument.pp) where it is actively maintained.

An older version is available at Lazarus-CCR and kept for compatibility, but not maintained any more: http://sourceforge.net/projects/lazarus-ccr/files/CsvDocument/CsvDocument%200.5/csvdocument-0.5.zip/download

Change Log

Version 0.1 (2010-01-22)

Version 0.2 (2010-05-31)

Version 0.3 (2011-01-14)

Version 0.4 (2011-05-10)

Version 0.5 (2014-10-25)

Since move to FCL (2015-04-04)

Installation

No "real" installation needed. Simply include unit CsvDocument and/or csvreadwrite in the uses section.

Usage examples

Extracting a specific cell from a CSV document

pascal
uses 
  csvdocument;

function ReadCSVCell(AFileName: String; ARow, ACol: Integer): String;
var 
  CSVDoc:TCSVDocument;
begin
  CSVDoc := TCSVDocument.Create;
  try
    CSVDoc.Delimiter := ';';
    CSVDoc.LoadFromFile(AFileName);
    Result := CSVDoc.Cells[ACol, ARow];
  finally
    CSVDoc.Free;
  end;
end;

Loading a csv document into a StringGrid

This sample code uses TCSVParser from the csvreadwrite unit to load a CSV/TSV/semicolon-separated file into a stringgrid, similar to StringGrid.LoadFromCSVFile but it supports all file format variations that CSVDocument supports.

The advantage of using TCSVParser versus TCSVDocument is that you can e.g. parse only the first 20 rows and load them into the grid, which saves a lot of memory if dealing with large CSV files.

pascal
unit stringgridutil;
{ Use csvreadwrite to import csv data into stringgrid. Offers more robust support for CSV file variations than TStringGrid.LoadFromCSVFile }

{$mode objfpc}{$H+} 
interface

uses
  Classes, SysUtils, Grids, csvreadwrite, LazFileUtils;
  // replace "csvreadwrite" by "csvdocument" if you use the out-dated version from CCR.

procedure LoadGridFromCSVFile(Grid: TStringGrid;AFilename: string;
  ADelimiter:Char=','; WithHeader:boolean=true; AddRows:boolean=true);
// Loads (quasi)CSV document in AFilename into Grid, using ADelimiter as
// delimiter. If WithHeader is true, it won't import the first row.
// If AddRows is true, it will add rows if the existing grid is too short.

implementation

procedure LoadGridFromCSVFile(Grid: TStringGrid;AFilename: string;
  ADelimiter:Char=','; WithHeader:boolean=true;AddRows:boolean=true);
const
  DefaultRowCount=10; //Number of rows to show by default
var
  FileStream: TFileStream;
  Parser: TCSVParser;
  RowOffset: integer;
begin
  Grid.BeginUpdate;
  // Reset the grid:
  Grid.Clear;
  Grid.RowCount:=DefaultRowCount;
  Grid.ColCount:=6; //Vaguely sensible
  if not(FileExistsUTF8(AFileName)) then exit;

  Parser:=TCSVParser.Create;
  FileStream := TFileStream.Create(AFilename, fmOpenRead+fmShareDenyWrite);
  try
    Parser.Delimiter:=ADelimiter;
    Parser.SetSource(FileStream);

    // If the grid has fixed rows, those will not receive data, so we need to
    // calculate the offset
    RowOffset:=Grid.FixedRows;
    // However, if we have a header row in our CSV data, we need to
    // discount that
    if WithHeader then RowOffset:=RowOffset-1;

    while Parser.ParseNextCell do
    begin
      // Stop if we've filled all existing rows. Todo: check for fixed grids etc, but not relevant for our case
      if AddRows=false then
        if Parser.CurrentRow+1>Grid.RowCount then break; //VisibleRowCount doesn't seem to work.

      // Widen grid if necessary. Slimming the grid will come after import done.
      if Grid.Columns.Enabled then
      begin
        if Grid.Columns.VisibleCount<Parser.CurrentCol+1 then Grid.Columns.Add;
      end
      else
      begin
        if Grid.ColCount<Parser.CurrentCol+1 then Grid.ColCount:=Parser.CurrentCol+1;
      end;

      // If header data found, and a fixed row is available, set the caption
      if (WithHeader) and
        (Parser.CurrentRow=0) and
        (Parser.CurrentRow<Grid.FixedRows-1) then
      begin
        // Assign header data to the first fixed row in the grid:
        Grid.Columns[Parser.CurrentCol].Title.Caption:=Parser.CurrentCellText;
      end;

      // Actual data import into grid cell, minding fixed rows and header
      if Grid.RowCount<Parser.CurrentRow+1 then
        Grid.RowCount:=Parser.CurrentRow+1;
      Grid.Cells[Parser.CurrentCol,Parser.CurrentRow+RowOffset]:=Parser.CurrentCellText;
    end;

    // Now we know the widest row in the import, we can snip the grid's
    // columns if necessary.
    if Grid.Columns.Enabled then
    begin
      while Grid.Columns.VisibleCount>Parser.MaxColCount do
      begin
        Grid.Columns.Delete(Grid.Columns.Count-1);
      end;
    end
    else
    begin
      if Grid.ColCount>Parser.MaxColCount then
        Grid.ColCount:=Parser.MaxColCount;
    end;

  finally
    Parser.Free;
    FileStream.Free;
    Grid.EndUpdate;
  end;
end;
end.

Contact

Please send bug reports and patches to the FPC gitlab bugtracker (https://gitlab.com/freepascal.org/fpc/source/-/issues))

See Also


From the Free Pascal wiki, page "CsvDocument", as it stood on 2022-06-29 after a change by Wp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 1, last changed by WikiArchive .

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.