导入CSV文件时网格超出范围错误

时间:2014-07-12 22:54:55

标签: class delphi csv import tstringgrid

关于将CSV文件导入Delphi,我正在关注this tutorial。我起草了下面提供的代码。该程序编译没有问题,但当我尝试执行函数来读取文件时,我得到网格超出范围错误消息。

unit geoimp;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.Buttons, Vcl.StdCtrls,
  Vcl.Grids, Vcl.DBGrids, Data.DB, Datasnap.DBClient;


 const
  shfolder = 'ShFolder.dll';

type
  TMainForm = class(TForm)
    MainPageControl: TPageControl;
    ImportTab: TTabSheet;
    MapPreviewTab: TTabSheet;
    GeoMatchingTab: TTabSheet;
    ImportLbl: TLabel;
    SlctImportDta: TSpeedButton;
    MainOpenDialog: TOpenDialog;
    MainListBox: TListBox;
    SG1: TStringGrid;
    procedure SlctImportDtaClick(Sender: TObject);

  private
    { Private declarations }
    procedure ParseRecord(sRecord: string; Row: integer);
     procedure ReadCSVFile;

  public
    { Public declarations }
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}





procedure TMainForm.ParseRecord(sRecord: string; Row: integer);
var
  Col, PosComma: integer;
  sField: string;
begin
  sRecord := StringReplace(sRecord, '"', '',
                           [rfReplaceAll]    ); // 1.
  Col := 0;    // first column of stringgrid
  repeat
    PosComma := Pos(',', sRecord);              // 2.
    if PosComma > 0 then
      sField := Copy(sRecord, 1, PosComma - 1)  // 3.a
    else
      sField := sRecord;                        // 3.b
    SG1.Cells[Col, Row] := sField;              // 4.
    if PosComma > 0 then begin                  // 5.
      Delete(sRecord, 1, PosComma);
      Col := Col + 1;                           // next column
    end;
  until PosComma = 0;                           // 6.
end;

procedure TMainForm.ReadCSVFile;
var
  FileName1, sRecord: string;
  Row: integer;
begin
  FileName1 := MainOpenDialog.FileName;
  MainListBox.Items.LoadFromFile(FileName1);
  SG1.RowCount := MainListBox.Items.Count;

  for Row := 0 to MainListBox.Items.Count - 1 do begin
    sRecord := MainListBox.Items[Row];
    ParseRecord(sRecord, Row);
  end;

  // 5. Select first "data" cell
  SG1.Row := 1;
  SG1.Col := 0;
  SG1.SetFocus;

end;


procedure TMainForm.SlctImportDtaClick(Sender: TObject);
begin

  // Create the open dialog object - assign to our open dialog variable
  MainOpenDialog := TOpenDialog.Create(self);

  // Set up the starting directory to be the current one
  MainOpenDialog.InitialDir := GetCurrentDir;

  // Only allow existing files to be selected
  MainOpenDialog.Options := [ofFileMustExist];

  // Allow only .dpr and .pas files to be selected
  MainOpenDialog.Filter :=
    'CSV Files|*.csv';

  // Select pascal files as the starting filter type
  MainOpenDialog.FilterIndex := 2;

  // Display the open file dialog
  if MainOpenDialog.Execute
  then ReadCSVFile
  else ShowMessage('Open file was cancelled');

  // Free up the dialog
  MainOpenDialog.Free;
end;

end.

1 个答案:

答案 0 :(得分:1)

在没有看到数据的情况下,您通过从输入字符串中删除引号来做出一些危险的假设。将逗号嵌入CSV文件中的引用字符串中是完全有效的 - 事实上,这就是它们允许引用字符串的原因。您只需要在一条记录中使用一个嵌入式逗号,如果您没有定义足够的列,它就会爆炸。

您没有显示如何设置网格的ColCount。默认情况下,它设置为5。

还需要在RowCount / ColCount中容纳FixedRows / FixedColumns值。

在第6行上方,你可以插入:

if (col >= (SG1.ColCount+SG1.FixedColumns)) then
  SG1.ColCount := SG1.ColCount + 1;

这将增加网格中的列数,并允许您查看嵌入CSV数据中引用字符串内的任何错误逗号的结果。

在您设置SG1.RowCount的ReadCSVFile的第3行中,如果SG1.FixedRows>它将会很短。 0

这些都是您获得例外的可能原因。