Reputation: 6868
What I need to do is read table details from excel file and want to create .pas file from it.
For the read-write purpose, I've used record type in delphi 7.
Here is the code what I've tried till now:
unit fImportFile;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
tSourceFile: TEdit;
dlgSourceFile: TOpenDialog;
btnImport: TButton;
procedure tSourceFileClick(Sender: TObject);
procedure btnImportClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TTableDetails = record
fTableName: String;
end;
TFieldDetails = record
fFieldName: String;
fType: String;
fShortAlias: String;
fLongAlias: String;
fDomainName: String;
fFieldAttributes:TStringList;
fComments: String;
end;
var
Form1: TForm1;
implementation
uses ComObj, uFileGeneration;
{$R *.dfm}
procedure TForm1.tSourceFileClick(Sender: TObject);
begin
with dlgSourceFile do
begin
FileName := tSourceFile.Text;
if ExtractFilePath(FileName) <> '' then
InitialDir := ExtractFilePath(FileName);
if Execute then
if FileName <> '' then
tSourceFile.Text := FileName;
end;
end;
procedure TForm1.btnImportClick(Sender: TObject);
const
cEndOfTables = '';
cTable = 'Table';
cTableCell = 2;
cTableNameCell = 3; // TableNameField
cFieldName = 'Field Name';
var
Excel: OleVariant;
iRow: Integer;
aTableDetails: TTableDetails;
aFieldDetails: Array of TFieldDetails;
fieldCount: Integer;
iTableName, FldWithChar, FldWithoutChar: String;
FldList, WordList: TStringList;
FieldName: String;
begin
FldList := nil;
WordList := nil;
try
Excel := CreateOleObject('Excel.Application');
Excel.Visible := False;
Excel.Workbooks.Open(tSourceFile.Text);
iRow := 1;
while (Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> '') do //To exit loop when the excel record will read blank TableName
begin
if (Excel.ActiveSheet.Cells[iRow,cTableCell].Value = cTable) then
begin
iTableName := Excel.ActiveSheet.Cells[iRow,cTableNameCell].Value;
if (iTableName = '') then
begin
ShowMessage('Table Name cannot be blank.');
exit;
end;
aTableDetails.fTableName := iTableName;
Inc(iRow);
fieldCount := 0;
FldList := TStringList.Create;
WordList := TStringList.Create;
ShowMessage('1 -- iRow --> ' + IntToStr(iRow));
while (Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> '') AND
(Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> cTable) do //Will create record until another table will found
begin
ShowMessage('2 -- Excel.ActiveSheet.Cells[iRow,cTableNameCell].Value = ' + Excel.ActiveSheet.Cells[iRow,cTableNameCell].Value);
FieldName := Excel.ActiveSheet.Cells[iRow,cTableNameCell].Value;
aFieldDetails[fieldCount].fFieldName := FieldName; //ERROR LINE
ShowMessage('3 -- iRow --> ' + IntToStr(iRow));
FldWithChar := aFieldDetails[fieldCount].fFieldName;
FldWithoutChar := NameWithoutAnyChar(FldWithChar, WordList);
FldList.Add(FldWithChar + '=' + FldWithoutChar);
WordList.Clear;
ShowMessage('4 -- iRow --> ' + IntToStr(iRow));
if (aFieldDetails[fieldCount].fFieldName = '') then
begin
ShowMessage('Field Name cannot be blank. TableName: '+iTableName);
exit;
end;
aFieldDetails[fieldCount].fType := Excel.ActiveSheet.Cells[iRow,3].Value;
aFieldDetails[fieldCount].fShortAlias := Excel.ActiveSheet.Cells[iRow,4].Value;
aFieldDetails[fieldCount].fLongAlias := Excel.ActiveSheet.Cells[iRow,5].Value;
aFieldDetails[fieldCount].fDomainName := Excel.ActiveSheet.Cells[iRow,6].Value;
aFieldDetails[fieldCount].fFieldAttributes.CommaText := Excel.ActiveSheet.Cells[iRow,7].Value;
aFieldDetails[fieldCount].fComments := Excel.ActiveSheet.Cells[iRow,8].Value;
Inc(fieldCount);
Inc(iRow);
end;
//Once new table row will be fouund it will call below method to create a dataview file for current table
ShowMessage('5 -- iRow --> ' + IntToStr(iRow));
GenerateDataviewFiles(aTableDetails, aFieldDetails, FldList, fieldCount-1);
ShowMessage('6 -- iRow --> ' + IntToStr(iRow));
end; //End of If condition
end; //End of outer most while loop
finally
FreeAndNil(WordList);
FreeAndNil(FldList);
Excel.Workbooks.Close;
Excel.Quit;
Excel := Unassigned;
end;
end;
end.
I've commented //ERROR LINE where I'm getting error for access violation.
What I'm doing here is, creating array of TFieldDetails and wanted to loop through it in another file.
Please help me through this as I am a new to delphi.
Upvotes: 1
Views: 501
Reputation: 2815
You forgot to initialize dynamic array aFieldDetails
. Thus, its length is still zero when you try to write to it with an index fieldCount
.
If you know the total count of fields, you should preallocate the full array by calling
SetLength(aFieldDetails, TheTotalFieldCount);
If you don't know the total count beforehand, you may use a list or another dynamic data structure, because reallocating every time you add an item is very expensive in terms of performance.
aFieldDetailList := TList.Create;
try
while (Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> '') AND
(Excel.ActiveSheet.Cells[iRow,cTableCell].Value <> cTable) do //Will create record until another table will found
begin
New(aFieldDetail); // create a new instance of aFieldDetail; aFieldDetail is of pointer type "^TFieldDetails"
// do your loop work
end;
// do your after-loop work
finally
// free all allocated memory
for aFieldDetail in aFieldDetailList do
Dispose(aFieldDetail);
FreeAndNil(aFieldDetailList);
end;
Upvotes: 3
Reputation: 2935
The problem is that you're trying to access an index of aFieldDetails
which is out of bounds. You should set length of a dynamic array before that. Like this:
...
SetLength(aFieldDetails, fieldCount+1);
aFieldDetails[fieldCount].fFieldName := FieldName; //ERROR LINE
...
However, this has a poor performance unless you know how many total fields you have since the beginning. It's because everytime SetLength
gets called, another block of memory is allocated and the whole array is copied to it.
I suggest you to use TList
which tries to keep performance in a good shape even if you don't know how many items are gonna be added to your list.
Upvotes: 4