You've already forked lazarus-ccr
fpspreadsheet: Extend TBufStream for reading. Rename workbook's WritingOptions to Options, and the option flags from woXXXX to boXXXX. Use boBufStream (former woBufStream) to activate TBufStream for reading of xls and ods. Speed up reading of biff2 by factor 3 (rel to commit before prev one). Fix pile-up of temporary files when saving ods.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3357 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -45,10 +45,8 @@ type
|
|||||||
var AValue: Variant; var AStyleCell: PCell);
|
var AValue: Variant; var AStyleCell: PCell);
|
||||||
procedure ReadFromIni;
|
procedure ReadFromIni;
|
||||||
procedure WriteToIni;
|
procedure WriteToIni;
|
||||||
procedure RunReadTest(Idx: Integer; Log: String;
|
procedure RunReadTest(Idx: Integer; Log: String; Options: TsWorkbookOptions);
|
||||||
Options: TsWorkbookWritingOptions);
|
procedure RunWriteTest(Idx: integer; Rows: integer; Log: string; Options: TsWorkbookOptions);
|
||||||
procedure RunWriteTest(Idx: integer; Rows: integer; Log: string;
|
|
||||||
Options: TsWorkbookWritingOptions);
|
|
||||||
procedure StatusMsg(const AMsg: String);
|
procedure StatusMsg(const AMsg: String);
|
||||||
public
|
public
|
||||||
{ public declarations }
|
{ public declarations }
|
||||||
@@ -80,6 +78,8 @@ const
|
|||||||
rc100k = 6;
|
rc100k = 6;
|
||||||
|
|
||||||
CONTENT_PREFIX: array[0..2] of Char = ('S', 'N', 'M');
|
CONTENT_PREFIX: array[0..2] of Char = ('S', 'N', 'M');
|
||||||
|
CONTENT_TEXT: array[0..2] of string = ('strings only', 'numbers only', '50% strings and 50% numbers');
|
||||||
|
|
||||||
FORMAT_EXT: array[0..4] of String = ('.ods', '.xlsx', '.xls', '_b5.xls', '_b2.xls');
|
FORMAT_EXT: array[0..4] of String = ('.ods', '.xlsx', '.xls', '_b5.xls', '_b2.xls');
|
||||||
SPREAD_FORMAT: array[0..4] of TsSpreadsheetFormat = (sfOpenDocument, sfOOXML, sfExcel8, sfExcel5, sfExcel2);
|
SPREAD_FORMAT: array[0..4] of TsSpreadsheetFormat = (sfOpenDocument, sfOOXML, sfExcel8, sfExcel5, sfExcel2);
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm1.RunReadTest(Idx: Integer; Log: String;
|
procedure TForm1.RunReadTest(Idx: Integer; Log: String;
|
||||||
Options: TsWorkbookWritingOptions);
|
Options: TsWorkbookOptions);
|
||||||
var
|
var
|
||||||
MyWorkbook: TsWorkbook;
|
MyWorkbook: TsWorkbook;
|
||||||
MyWorksheet: TsWorksheet;
|
MyWorksheet: TsWorksheet;
|
||||||
@@ -127,9 +127,7 @@ var
|
|||||||
ok: Boolean;
|
ok: Boolean;
|
||||||
begin
|
begin
|
||||||
s := Trim(Log);
|
s := Trim(Log);
|
||||||
|
|
||||||
Log := Log + ' ';
|
Log := Log + ' ';
|
||||||
|
|
||||||
try
|
try
|
||||||
for i := 0 to CgFormats.Items.Count-1 do begin
|
for i := 0 to CgFormats.Items.Count-1 do begin
|
||||||
if FEscape then begin
|
if FEscape then begin
|
||||||
@@ -162,6 +160,7 @@ begin
|
|||||||
MyWorkbook := TsWorkbook.Create;
|
MyWorkbook := TsWorkbook.Create;
|
||||||
try
|
try
|
||||||
Application.ProcessMessages;
|
Application.ProcessMessages;
|
||||||
|
MyWorkbook.Options := Options;
|
||||||
Tm := GetTickCount;
|
Tm := GetTickCount;
|
||||||
try
|
try
|
||||||
MyWorkbook.ReadFromFile(fname, SPREAD_FORMAT[i]);
|
MyWorkbook.ReadFromFile(fname, SPREAD_FORMAT[i]);
|
||||||
@@ -184,7 +183,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm1.RunWriteTest(Idx: integer; Rows: integer; Log: string;
|
procedure TForm1.RunWriteTest(Idx: integer; Rows: integer; Log: string;
|
||||||
Options: TsWorkbookWritingOptions);
|
Options: TsWorkbookOptions);
|
||||||
var
|
var
|
||||||
MyWorkbook: TsWorkbook;
|
MyWorkbook: TsWorkbook;
|
||||||
MyWorksheet: TsWorksheet;
|
MyWorksheet: TsWorksheet;
|
||||||
@@ -201,13 +200,13 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
MyWorksheet := MyWorkbook.AddWorksheet('Sheet1');
|
MyWorksheet := MyWorkbook.AddWorksheet('Sheet1');
|
||||||
MyWorkbook.WritingOptions := Options;
|
MyWorkbook.Options := Options;
|
||||||
|
|
||||||
Application.ProcessMessages;
|
Application.ProcessMessages;
|
||||||
Tm := GetTickCount;
|
Tm := GetTickCount;
|
||||||
|
|
||||||
try
|
try
|
||||||
if woVirtualMode in Options then
|
if boVirtualMode in Options then
|
||||||
begin
|
begin
|
||||||
MyWorkbook.VirtualRowCount := Rows;
|
MyWorkbook.VirtualRowCount := Rows;
|
||||||
MyWorkbook.VirtualColCount := COLCOUNT;
|
MyWorkbook.VirtualColCount := COLCOUNT;
|
||||||
@@ -222,7 +221,7 @@ begin
|
|||||||
for ARow := 0 to Rows - 1 do
|
for ARow := 0 to Rows - 1 do
|
||||||
begin
|
begin
|
||||||
if ARow mod 1000 = 0 then begin
|
if ARow mod 1000 = 0 then begin
|
||||||
StatusMsg(Format('Populating row %d', [ARow]));
|
StatusMsg(Format('Building row %d...', [ARow]));
|
||||||
if FEscape then begin
|
if FEscape then begin
|
||||||
Log := 'Test aborted';
|
Log := 'Test aborted';
|
||||||
exit;
|
exit;
|
||||||
@@ -236,7 +235,8 @@ begin
|
|||||||
1: for ACol := 0 to COLCOUNT-1 do
|
1: for ACol := 0 to COLCOUNT-1 do
|
||||||
MyWorksheet.WriteNumber(ARow, ACol, 1E5*ARow + ACol);
|
MyWorksheet.WriteNumber(ARow, ACol, 1E5*ARow + ACol);
|
||||||
2: for ACol := 0 to COLCOUNT-1 do
|
2: for ACol := 0 to COLCOUNT-1 do
|
||||||
if (odd(ARow) and odd(ACol)) or odd(ARow+ACol) then begin
|
if (odd(ARow) and odd(ACol)) or odd(ARow+ACol) then
|
||||||
|
begin
|
||||||
S := 'Xy' + IntToStr(ARow) + 'x' + IntToStr(ACol);
|
S := 'Xy' + IntToStr(ARow) + 'x' + IntToStr(ACol);
|
||||||
MyWorksheet.WriteUTF8Text(ARow, ACol, S);
|
MyWorksheet.WriteUTF8Text(ARow, ACol, S);
|
||||||
end else
|
end else
|
||||||
@@ -255,7 +255,8 @@ begin
|
|||||||
|
|
||||||
Log := Log + ' ' + format('%5.1f ', [(GetTickCount - Tm) / 1000]);
|
Log := Log + ' ' + format('%5.1f ', [(GetTickCount - Tm) / 1000]);
|
||||||
|
|
||||||
for k := 0 to CgFormats.Items.Count-1 do begin
|
for k := 0 to CgFormats.Items.Count-1 do
|
||||||
|
begin
|
||||||
if FEscape then begin
|
if FEscape then begin
|
||||||
Log := 'Test aborted';
|
Log := 'Test aborted';
|
||||||
exit;
|
exit;
|
||||||
@@ -313,16 +314,11 @@ begin
|
|||||||
FEscape := false;
|
FEscape := false;
|
||||||
EnableControls(false);
|
EnableControls(false);
|
||||||
|
|
||||||
try
|
|
||||||
Memo.Append ('Running: Reading TsWorkbook from various file formats');
|
Memo.Append ('Running: Reading TsWorkbook from various file formats');
|
||||||
case RgContent.ItemIndex of
|
Memo.Append (' Worksheet contains ' + CONTENT_TEXT[RgContent.ItemIndex]);
|
||||||
0: Memo.Append(' Worksheet contains strings only');
|
|
||||||
1: Memo.Append(' Worksheet contains numbers only');
|
|
||||||
2: Memo.Append(' Worksheet contains 50% strings and 50% numbers');
|
|
||||||
end;
|
|
||||||
Memo.Append (' (Times in seconds)');
|
Memo.Append (' (Times in seconds)');
|
||||||
//'----------- .ods .xlsx biff8 biff5 biff2');
|
//'----------- .ods .xlsx biff8 biff5 biff2');
|
||||||
//'Rows x Cols W.Options Build Write Write Write Write Write'
|
//'Rows x Cols Options Build Write Write Write Write Write'
|
||||||
s := '-------------------------------- ';
|
s := '-------------------------------- ';
|
||||||
if CgFormats.Checked[fmtODS] then s := s + ' .ods ';
|
if CgFormats.Checked[fmtODS] then s := s + ' .ods ';
|
||||||
if CgFormats.Checked[fmtXLSX] then s := s + '.xlsx ';
|
if CgFormats.Checked[fmtXLSX] then s := s + '.xlsx ';
|
||||||
@@ -330,7 +326,7 @@ begin
|
|||||||
if CgFormats.Checked[fmtXLS5] then s := s + 'biff5 ';
|
if CgFormats.Checked[fmtXLS5] then s := s + 'biff5 ';
|
||||||
if CgFormats.Checked[fmtXLS2] then s := s + 'biff2';
|
if CgFormats.Checked[fmtXLS2] then s := s + 'biff2';
|
||||||
Memo.Append(TrimRight(s));
|
Memo.Append(TrimRight(s));
|
||||||
s := 'Rows x Cols W.Options ';
|
s := 'Rows x Cols Options ';
|
||||||
if CgFormats.Checked[fmtODS] then s := s + ' Read ';
|
if CgFormats.Checked[fmtODS] then s := s + ' Read ';
|
||||||
if CgFormats.Checked[fmtXLSX] then s := s + ' Read ';
|
if CgFormats.Checked[fmtXLSX] then s := s + ' Read ';
|
||||||
if CgFormats.Checked[fmtXLS8] then s := s + ' Read ';
|
if CgFormats.Checked[fmtXLS8] then s := s + ' Read ';
|
||||||
@@ -341,6 +337,7 @@ begin
|
|||||||
len := Length(s);
|
len := Length(s);
|
||||||
Memo.Append(DupeString('-', len));
|
Memo.Append(DupeString('-', len));
|
||||||
|
|
||||||
|
try
|
||||||
for i:=0 to CgRowCount.Items.Count-1 do begin
|
for i:=0 to CgRowCount.Items.Count-1 do begin
|
||||||
if FEscape then
|
if FEscape then
|
||||||
exit;
|
exit;
|
||||||
@@ -351,12 +348,16 @@ begin
|
|||||||
rows := GetRowCount(i);
|
rows := GetRowCount(i);
|
||||||
s := Format('%7.0nx%d', [1.0*rows, COLCOUNT]);
|
s := Format('%7.0nx%d', [1.0*rows, COLCOUNT]);
|
||||||
|
|
||||||
|
if CbVirtualModeOnly.Checked then begin
|
||||||
|
//RunReadTest(2, s + ' [boVM ]', [boVirtualMode]);
|
||||||
|
//RunReadTest(4, s + ' [boVM, boBS]', [boVirtualMode, boBufStream]);
|
||||||
|
end else begin
|
||||||
RunReadTest(1, s + ' [ ]', []);
|
RunReadTest(1, s + ' [ ]', []);
|
||||||
(*
|
//RunReadTest(2, s + ' [boVM ]', [boVirtualMode]);
|
||||||
RunReadTest(2, s + ' [woVM ]', [woVirtualMode]);
|
RunReadTest(3, s + ' [ boBS]', [boBufStream]);
|
||||||
RunReadTest(3, s + ' [ woBS]', [woBufStream]);
|
//RunReadTest(4, s + ' [boVM, boBS]', [boVirtualMode, boBufStream]);
|
||||||
RunReadTest(4, s + ' [woVM, woBS]', [woVirtualMode, woBufStream]);
|
end;
|
||||||
*)
|
|
||||||
Memo.Append(DupeString('-', len));
|
Memo.Append(DupeString('-', len));
|
||||||
end;
|
end;
|
||||||
Memo.Append('Ready');
|
Memo.Append('Ready');
|
||||||
@@ -378,14 +379,10 @@ begin
|
|||||||
EnableControls(false);
|
EnableControls(false);
|
||||||
|
|
||||||
Memo.Append ('Running: Building TsWorkbook and writing to different file formats');
|
Memo.Append ('Running: Building TsWorkbook and writing to different file formats');
|
||||||
case RgContent.ItemIndex of
|
Memo.Append (' Worksheet contains ' + CONTENT_TEXT[RgContent.ItemIndex]);
|
||||||
0: Memo.Append(' Worksheet contains strings only');
|
|
||||||
1: Memo.Append(' Worksheet contains numbers only');
|
|
||||||
2: Memo.Append(' Worksheet contains 50% strings and 50% numbers');
|
|
||||||
end;
|
|
||||||
Memo.Append (' (Times in seconds)');
|
Memo.Append (' (Times in seconds)');
|
||||||
//'----------- .ods .xlsx biff8 biff5 biff2');
|
//'----------- .ods .xlsx biff8 biff5 biff2');
|
||||||
//'Rows x Cols W.Options Build Write Write Write Write Write'
|
//'Rows x Cols Options Build Write Write Write Write Write'
|
||||||
s := '-------------------------------- ';
|
s := '-------------------------------- ';
|
||||||
if CgFormats.Checked[fmtODS] then s := s + ' .ods ';
|
if CgFormats.Checked[fmtODS] then s := s + ' .ods ';
|
||||||
if CgFormats.Checked[fmtXLSX] then s := s + '.xlsx ';
|
if CgFormats.Checked[fmtXLSX] then s := s + '.xlsx ';
|
||||||
@@ -393,7 +390,7 @@ begin
|
|||||||
if CgFormats.Checked[fmtXLS5] then s := s + 'biff5 ';
|
if CgFormats.Checked[fmtXLS5] then s := s + 'biff5 ';
|
||||||
if CgFormats.Checked[fmtXLS2] then s := s + 'biff2';
|
if CgFormats.Checked[fmtXLS2] then s := s + 'biff2';
|
||||||
Memo.Append(TrimRight(s));
|
Memo.Append(TrimRight(s));
|
||||||
s := 'Rows x Cols W.Options Build ';
|
s := 'Rows x Cols Options Build ';
|
||||||
if CgFormats.Checked[fmtODS] then s := s + 'Write ';
|
if CgFormats.Checked[fmtODS] then s := s + 'Write ';
|
||||||
if CgFormats.Checked[fmtXLSX] then s := s + 'Write ';
|
if CgFormats.Checked[fmtXLSX] then s := s + 'Write ';
|
||||||
if CgFormats.Checked[fmtXLS8] then s := s + 'Write ';
|
if CgFormats.Checked[fmtXLS8] then s := s + 'Write ';
|
||||||
@@ -414,13 +411,13 @@ begin
|
|||||||
Rows := GetRowCount(i);
|
Rows := GetRowCount(i);
|
||||||
s := Format('%7.0nx%d', [1.0*Rows, COLCOUNT]);
|
s := Format('%7.0nx%d', [1.0*Rows, COLCOUNT]);
|
||||||
if CbVirtualModeOnly.Checked then begin
|
if CbVirtualModeOnly.Checked then begin
|
||||||
RunWriteTest(2, Rows, s + ' [woVM ]', [woVirtualMode]);
|
RunWriteTest(2, Rows, s + ' [boVM ]', [boVirtualMode]);
|
||||||
RunWriteTest(4, Rows, s + ' [woVM, woBS]', [woVirtualMode, woBufStream]);
|
RunWriteTest(4, Rows, s + ' [boVM, boBS]', [boVirtualMode, boBufStream]);
|
||||||
end else begin
|
end else begin
|
||||||
RunWriteTest(1, Rows, s + ' [ ]', []);
|
RunWriteTest(1, Rows, s + ' [ ]', []);
|
||||||
RunWriteTest(2, Rows, s + ' [woVM ]', [woVirtualMode]);
|
RunWriteTest(2, Rows, s + ' [boVM ]', [boVirtualMode]);
|
||||||
RunWriteTest(3, Rows, s + ' [ woBS]', [woBufStream]);
|
RunWriteTest(3, Rows, s + ' [ boBS]', [boBufStream]);
|
||||||
RunWriteTest(4, Rows, s + ' [woVM, woBS]', [woVirtualMode, woBufStream]);
|
RunWriteTest(4, Rows, s + ' [boVM, boBS]', [boVirtualMode, boBufStream]);
|
||||||
end;
|
end;
|
||||||
Memo.Append(DupeString('-', len));
|
Memo.Append(DupeString('-', len));
|
||||||
end;
|
end;
|
||||||
@@ -450,6 +447,7 @@ begin
|
|||||||
CgRowCount.Enabled := AEnable;
|
CgRowCount.Enabled := AEnable;
|
||||||
LblCancel.Visible := not AEnable;
|
LblCancel.Visible := not AEnable;
|
||||||
StatusMsg('');
|
StatusMsg('');
|
||||||
|
Application.ProcessMessages;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm1.FormCreate(Sender: TObject);
|
procedure TForm1.FormCreate(Sender: TObject);
|
||||||
|
@@ -64,17 +64,17 @@ begin
|
|||||||
|
|
||||||
{ These are the essential commands to activate virtual mode: }
|
{ These are the essential commands to activate virtual mode: }
|
||||||
|
|
||||||
// workbook.WritingOptions := [woVirtualMode, woBufStream];
|
workbook.Options := [boVirtualMode, boBufStream];
|
||||||
workbook.WritingOptions := [woVirtualMode];
|
// workbook.Options := [boVirtualMode];
|
||||||
{ woBufStream can be omitted, but is important for large files: it causes
|
{ boBufStream can be omitted, but is important for large files: it causes
|
||||||
writing temporary data to a buffered file stream instead of a pure
|
writing temporary data to a buffered file stream instead of a pure
|
||||||
memory stream which can overflow memory. The option can slow down the
|
memory stream which can overflow memory. In cases, the option can slow
|
||||||
writing process a bit. }
|
down the writing process a bit. }
|
||||||
|
|
||||||
{ Next two numbers define the size of virtual spreadsheet.
|
{ Next two numbers define the size of virtual spreadsheet.
|
||||||
In case of a database, VirtualRowCount is the RecordCount, VirtualColCount
|
In case of a database, VirtualRowCount is the RecordCount, VirtualColCount
|
||||||
the number of fields to be written to the spreadsheet file }
|
the number of fields to be written to the spreadsheet file }
|
||||||
workbook.VirtualRowCount := 20000;
|
workbook.VirtualRowCount := 5000;
|
||||||
workbook.VirtualColCount := 100;
|
workbook.VirtualColCount := 100;
|
||||||
|
|
||||||
{ The event handler for OnNeedCellData links the workbook to the method
|
{ The event handler for OnNeedCellData links the workbook to the method
|
||||||
@@ -95,8 +95,10 @@ begin
|
|||||||
{ In case of a database, you would open the dataset before calling this: }
|
{ In case of a database, you would open the dataset before calling this: }
|
||||||
|
|
||||||
t := Now;
|
t := Now;
|
||||||
//workbook.WriteToFile('test_virtual.xlsx', sfOOXML, true);
|
workbook.WriteToFile('test_virtual.xlsx', sfOOXML, true);
|
||||||
workbook.WriteToFile('test_virtual.xls', sfExcel8, true);
|
//workbook.WriteToFile('test_virtual.xls', sfExcel8, true);
|
||||||
|
//workbook.WriteToFile('test_virtual.xls', sfExcel5, true);
|
||||||
|
//workbook.WriteToFile('test_virtual.xls', sfExcel2, true);
|
||||||
t := Now - t;
|
t := Now - t;
|
||||||
|
|
||||||
finally
|
finally
|
||||||
|
@@ -193,7 +193,7 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
StrUtils;
|
StrUtils, fpsStreams;
|
||||||
|
|
||||||
const
|
const
|
||||||
{ OpenDocument general XML constants }
|
{ OpenDocument general XML constants }
|
||||||
@@ -1191,8 +1191,23 @@ var
|
|||||||
parser: TDOMParser;
|
parser: TDOMParser;
|
||||||
src: TXMLInputSource;
|
src: TXMLInputSource;
|
||||||
stream: TStream;
|
stream: TStream;
|
||||||
|
// fstream: TStream;
|
||||||
begin
|
begin
|
||||||
|
{
|
||||||
|
if (boBufStream in Workbook.Options) then begin
|
||||||
|
fstream := TFileStream.Create(AFilename, fmOpenRead + fmShareDenyWrite);
|
||||||
|
stream := TMemorystream.Create;
|
||||||
|
stream.CopyFrom(fstream, fstream.Size);
|
||||||
|
stream.Position := 0;
|
||||||
|
fstream.free;
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boBufStream in Workbook.Options) then
|
||||||
|
stream := TBufStream.Create(AFileName, fmOpenRead + fmShareDenyWrite)
|
||||||
|
else
|
||||||
stream := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyWrite);
|
stream := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyWrite);
|
||||||
|
|
||||||
try
|
try
|
||||||
parser := TDOMParser.Create;
|
parser := TDOMParser.Create;
|
||||||
try
|
try
|
||||||
@@ -2239,7 +2254,14 @@ procedure TsSpreadOpenDocWriter.CreateStreams;
|
|||||||
var
|
var
|
||||||
dir: String;
|
dir: String;
|
||||||
begin
|
begin
|
||||||
if (woBufStream in Workbook.WritingOptions) then begin
|
if (boBufStream in Workbook.Options) then begin
|
||||||
|
FSMeta := TBufStream.Create(GetTempFileName('', 'fpsM'));
|
||||||
|
FSSettings := TBufStream.Create(GetTempFileName('', 'fpsS'));
|
||||||
|
FSStyles := TBufStream.Create(GetTempFileName('', 'fpsSTY'));
|
||||||
|
FSContent := TBufStream.Create(GetTempFileName('', 'fpsC'));
|
||||||
|
FSMimeType := TBufStream.Create(GetTempFileName('', 'fpsMT'));
|
||||||
|
FSMetaInfManifest := TBufStream.Create(GetTempFileName('', 'fpsMIM'));
|
||||||
|
{
|
||||||
dir := IncludeTrailingPathDelimiter(GetTempDir);
|
dir := IncludeTrailingPathDelimiter(GetTempDir);
|
||||||
FSMeta := TFileStream.Create(GetTempFileName(dir, 'fpsM'), fmCreate+fmOpenRead);
|
FSMeta := TFileStream.Create(GetTempFileName(dir, 'fpsM'), fmCreate+fmOpenRead);
|
||||||
FSSettings := TFileStream.Create(GetTempFileName(dir, 'fpsS'), fmCreate+fmOpenRead);
|
FSSettings := TFileStream.Create(GetTempFileName(dir, 'fpsS'), fmCreate+fmOpenRead);
|
||||||
@@ -2247,6 +2269,7 @@ begin
|
|||||||
FSContent := TFileStream.Create(GetTempFileName(dir, 'fpsC'), fmCreate+fmOpenRead);
|
FSContent := TFileStream.Create(GetTempFileName(dir, 'fpsC'), fmCreate+fmOpenRead);
|
||||||
FSMimeType := TFileStream.Create(GetTempFileName(dir, 'fpsMT'), fmCreate+fmOpenRead);
|
FSMimeType := TFileStream.Create(GetTempFileName(dir, 'fpsMT'), fmCreate+fmOpenRead);
|
||||||
FSMetaInfManifest := TFileStream.Create(GetTempFileName(dir, 'fpsMIM'), fmCreate+fmOpenRead);
|
FSMetaInfManifest := TFileStream.Create(GetTempFileName(dir, 'fpsMIM'), fmCreate+fmOpenRead);
|
||||||
|
}
|
||||||
end else begin;
|
end else begin;
|
||||||
FSMeta := TMemoryStream.Create;
|
FSMeta := TMemoryStream.Create;
|
||||||
FSSettings := TMemoryStream.Create;
|
FSSettings := TMemoryStream.Create;
|
||||||
|
@@ -699,22 +699,33 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Options considered when writing a workbook
|
Option flags for the workbook
|
||||||
|
|
||||||
@param woVirtualMode If in virtual mode date are not taken from cells
|
@param boVirtualMode If in virtual mode date are not taken from cells
|
||||||
when a spreadsheet is written to file, but are
|
when a spreadsheet is written to file, but are
|
||||||
provided by means of the event OnNeedCellData.
|
provided by means of the event OnNeedCellData.
|
||||||
@param woBufStream When this option is set a buffered stream is used
|
@param boBufStream When this option is set a buffered stream is used
|
||||||
for writing (a memory stream swapping to disk) }
|
for writing (a memory stream swapping to disk) or
|
||||||
TsWorkbookWritingOption = (woVirtualMode, woBufStream);
|
reading (a file stream pre-reading chunks of data
|
||||||
|
to memory) }
|
||||||
|
TsWorkbookOption = (boVirtualMode, boBufStream);
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Options considered when writing a workbook }
|
Set of options flags for the workbook }
|
||||||
TsWorkbookWritingOptions = set of TsWorkbookWritingOption;
|
TsWorkbookOptions = set of TsWorkbookOption;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Event fired when writing a file in virtual mode. The event handler has to
|
||||||
|
pass data ("AValue") and formatting ("AStyleCell") to the writer }
|
||||||
TsWorkbookNeedCellDataEvent = procedure(Sender: TObject; ARow, ACol: Cardinal;
|
TsWorkbookNeedCellDataEvent = procedure(Sender: TObject; ARow, ACol: Cardinal;
|
||||||
var AValue: variant; var AStyleCell: PCell) of object;
|
var AValue: variant; var AStyleCell: PCell) of object;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Event fired when reading a file in virtual mode. The event handler has to
|
||||||
|
process the data provided by the read in the "ADataCell". }
|
||||||
|
TsWorkbookHaveCellDataEvent = procedure(Sender: TObject; ARow, ACol: Cardinal;
|
||||||
|
const ADataCell: PCell) of object;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
The workbook contains the worksheets and provides methods for reading from
|
The workbook contains the worksheets and provides methods for reading from
|
||||||
and writing to file.
|
and writing to file.
|
||||||
@@ -734,8 +745,9 @@ type
|
|||||||
FVirtualColCount: Cardinal;
|
FVirtualColCount: Cardinal;
|
||||||
FVirtualRowCount: Cardinal;
|
FVirtualRowCount: Cardinal;
|
||||||
FWriting: Boolean;
|
FWriting: Boolean;
|
||||||
FWritingOptions: TsWorkbookWritingOptions;
|
FOptions: TsWorkbookOptions;
|
||||||
FOnNeedCellData: TsWorkbookNeedCellDataEvent;
|
FOnNeedCellData: TsWorkbookNeedCellDataEvent;
|
||||||
|
FOnHaveCellData: TsWorkbookHaveCellDataEvent;
|
||||||
FFileName: String;
|
FFileName: String;
|
||||||
|
|
||||||
{ Setter/Getter }
|
{ Setter/Getter }
|
||||||
@@ -824,11 +836,15 @@ type
|
|||||||
property ReadFormulas: Boolean read FReadFormulas write FReadFormulas;
|
property ReadFormulas: Boolean read FReadFormulas write FReadFormulas;
|
||||||
property VirtualColCount: cardinal read FVirtualColCount write SetVirtualColCount;
|
property VirtualColCount: cardinal read FVirtualColCount write SetVirtualColCount;
|
||||||
property VirtualRowCount: cardinal read FVirtualRowCount write SetVirtualRowCount;
|
property VirtualRowCount: cardinal read FVirtualRowCount write SetVirtualRowCount;
|
||||||
property WritingOptions: TsWorkbookWritingOptions read FWritingOptions write FWritingOptions;
|
property Options: TsWorkbookOptions read FOptions write FOptions;
|
||||||
{@@ This event allows to provide external cell data for writing to file,
|
{@@ This event allows to provide external cell data for writing to file,
|
||||||
standard cells are ignored. Intended for converting large database files
|
standard cells are ignored. Intended for converting large database files
|
||||||
to s spreadsheet format. Requires WritingOption woVirtualMode to be set. }
|
to a spreadsheet format. Requires Option boVirtualMode to be set. }
|
||||||
property OnNeedCellData: TsWorkbookNeedCellDataEvent read FOnNeedCellData write FOnNeedCellData;
|
property OnNeedCellData: TsWorkbookNeedCellDataEvent read FOnNeedCellData write FOnNeedCellData;
|
||||||
|
{@@ This event accepts cell data while reading a spreadsheet file. Data are
|
||||||
|
not encorporated in a spreadsheet, they are just passed through to the
|
||||||
|
event handler for processing. Requires Optio boVirtualMode to be set. }
|
||||||
|
property OnHaveCellData: TsWorkbookHaveCellDataEvent read FOnHaveCellData write FOnHaveCellData;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ Contents of a number format record }
|
{@@ Contents of a number format record }
|
||||||
@@ -4188,7 +4204,7 @@ var
|
|||||||
sheet: TsWorksheet;
|
sheet: TsWorksheet;
|
||||||
r1,r2, c1,c2: Cardinal;
|
r1,r2, c1,c2: Cardinal;
|
||||||
begin
|
begin
|
||||||
if (woVirtualMode in WritingOptions) then begin
|
if (boVirtualMode in Options) then begin
|
||||||
ALastRow := FVirtualRowCount - 1;
|
ALastRow := FVirtualRowCount - 1;
|
||||||
ALastCol := FVirtualColCount - 1;
|
ALastCol := FVirtualColCount - 1;
|
||||||
end else begin
|
end else begin
|
||||||
@@ -5313,9 +5329,28 @@ end;
|
|||||||
@see TsWorkbook
|
@see TsWorkbook
|
||||||
}
|
}
|
||||||
procedure TsCustomSpreadReader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
procedure TsCustomSpreadReader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
||||||
|
{
|
||||||
var
|
var
|
||||||
InputFile: TFileStream;
|
fs, ms: TStream;
|
||||||
begin
|
begin
|
||||||
|
fs := TFileStream.Create(AFileName, fmOpenRead);
|
||||||
|
ms := TMemoryStream.Create;
|
||||||
|
try
|
||||||
|
ms.CopyFrom(fs, fs.Size);
|
||||||
|
ms.Position := 0;
|
||||||
|
ReadFromStream(ms, AData);
|
||||||
|
finally
|
||||||
|
ms.Free;
|
||||||
|
fs.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
}
|
||||||
|
var
|
||||||
|
InputFile: TStream;
|
||||||
|
begin
|
||||||
|
if (boBufStream in Workbook.Options) then
|
||||||
|
InputFile := TBufStream.Create(AFileName, fmOpenRead)
|
||||||
|
else
|
||||||
InputFile := TFileStream.Create(AFileName, fmOpenRead);
|
InputFile := TFileStream.Create(AFileName, fmOpenRead);
|
||||||
try
|
try
|
||||||
ReadFromStream(InputFile, AData);
|
ReadFromStream(InputFile, AData);
|
||||||
@@ -5495,7 +5530,7 @@ procedure TsCustomSpreadWriter.GetSheetDimensions(AWorksheet: TsWorksheet;
|
|||||||
begin
|
begin
|
||||||
AFirstRow := 0;
|
AFirstRow := 0;
|
||||||
AFirstCol := 0;
|
AFirstCol := 0;
|
||||||
if (woVirtualMode in AWorksheet.Workbook.WritingOptions) then begin
|
if (boVirtualMode in AWorksheet.Workbook.Options) then begin
|
||||||
ALastRow := AWorksheet.Workbook.VirtualRowCount-1;
|
ALastRow := AWorksheet.Workbook.VirtualRowCount-1;
|
||||||
ALastCol := AWorksheet.Workbook.VirtualColCount-1;
|
ALastCol := AWorksheet.Workbook.VirtualColCount-1;
|
||||||
end else begin
|
end else begin
|
||||||
@@ -5751,7 +5786,7 @@ begin
|
|||||||
if AOverwriteExisting then lMode := fmCreate or fmOpenWrite
|
if AOverwriteExisting then lMode := fmCreate or fmOpenWrite
|
||||||
else lMode := fmCreate;
|
else lMode := fmCreate;
|
||||||
|
|
||||||
if (woBufStream in Workbook.WritingOptions) then
|
if (boBufStream in Workbook.Options) then
|
||||||
OutputFile := TBufStream.Create(AFileName, lMode)
|
OutputFile := TBufStream.Create(AFileName, lMode)
|
||||||
else
|
else
|
||||||
OutputFile := TFileStream.Create(AFileName, lMode);
|
OutputFile := TFileStream.Create(AFileName, lMode);
|
||||||
|
@@ -5,8 +5,8 @@ interface
|
|||||||
uses
|
uses
|
||||||
SysUtils, Classes;
|
SysUtils, Classes;
|
||||||
|
|
||||||
const
|
var
|
||||||
DEFAULT_STREAM_BUFFER_SIZE = 1024 * 1024;
|
DEFAULT_STREAM_BUFFER_SIZE: Integer = 1024 * 1024; // 1 MB
|
||||||
|
|
||||||
type
|
type
|
||||||
{ A buffered stream }
|
{ A buffered stream }
|
||||||
@@ -23,13 +23,15 @@ type
|
|||||||
procedure CreateFileStream;
|
procedure CreateFileStream;
|
||||||
function GetPosition: Int64; override;
|
function GetPosition: Int64; override;
|
||||||
function GetSize: Int64; override;
|
function GetSize: Int64; override;
|
||||||
|
function IsWritingMode: Boolean;
|
||||||
public
|
public
|
||||||
constructor Create(AFileName: String; AMode: Word;
|
constructor Create(AFileName: String; AMode: Word;
|
||||||
ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE); overload;
|
ABufSize: Cardinal = Cardinal(-1)); overload;
|
||||||
constructor Create(ATempFile: String; AKeepFile: Boolean = false;
|
constructor Create(ATempFile: String; AKeepFile: Boolean = false;
|
||||||
ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE); overload;
|
ABufSize: Cardinal = Cardinal(-1)); overload;
|
||||||
constructor Create(ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE); overload;
|
constructor Create(ABufSize: Cardinal = Cardinal(-1)); overload;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
procedure FillBuffer;
|
||||||
procedure FlushBuffer;
|
procedure FlushBuffer;
|
||||||
function Read(var Buffer; Count: Longint): Longint; override;
|
function Read(var Buffer; Count: Longint): Longint; override;
|
||||||
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
|
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
|
||||||
@@ -51,18 +53,19 @@ end;
|
|||||||
|
|
||||||
{@@
|
{@@
|
||||||
Constructor of the TBufStream. Creates a memory stream and prepares everything
|
Constructor of the TBufStream. Creates a memory stream and prepares everything
|
||||||
to create also a file stream if the streamsize exceeds ABufSize bytes.
|
to create also a file stream if the stream size exceeds ABufSize bytes.
|
||||||
|
|
||||||
@param ATempFile File name for the file stream. If an empty string is
|
@param ATempFile File name for the file stream. If an empty string is
|
||||||
used a temporary file name is created by calling GetTempFileName.
|
used a temporary file name is created by calling GetTempFileName.
|
||||||
@param AKeepFile If true the stream is flushed to file when the stream is
|
@param AKeepFile If true and the stream is in WritingMode the stream is
|
||||||
|
flushed to file when the stream is
|
||||||
destroyed. If false the file is deleted when the stream
|
destroyed. If false the file is deleted when the stream
|
||||||
is destroyed.
|
is destroyed.
|
||||||
@param ABufSize Maximum size of the memory stream before swapping to file
|
@param ABufSize Maximum size of the memory stream before swapping to file
|
||||||
starts. Value is given in bytes.
|
starts. Value is given in bytes.
|
||||||
}
|
}
|
||||||
constructor TBufStream.Create(ATempFile: String; AKeepFile: Boolean = false;
|
constructor TBufStream.Create(ATempFile: String; AKeepFile: Boolean = false;
|
||||||
ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE);
|
ABufSize: Cardinal = Cardinal(-1));
|
||||||
begin
|
begin
|
||||||
if ATempFile = '' then
|
if ATempFile = '' then
|
||||||
ATempFile := ChangeFileExt(GetTempFileName, '.~abc');
|
ATempFile := ChangeFileExt(GetTempFileName, '.~abc');
|
||||||
@@ -73,6 +76,9 @@ begin
|
|||||||
FMemoryStream := TMemoryStream.Create;
|
FMemoryStream := TMemoryStream.Create;
|
||||||
// The file stream is only created when needed because of possible conflicts
|
// The file stream is only created when needed because of possible conflicts
|
||||||
// of random file names.
|
// of random file names.
|
||||||
|
if ABufSize = Cardinal(-1) then
|
||||||
|
FBufSize := DEFAULT_STREAM_BUFFER_SIZE
|
||||||
|
else
|
||||||
FBufSize := ABufSize;
|
FBufSize := ABufSize;
|
||||||
FFileMode := fmCreate + fmOpenRead;
|
FFileMode := fmCreate + fmOpenRead;
|
||||||
end;
|
end;
|
||||||
@@ -86,7 +92,7 @@ end;
|
|||||||
@param ABufSize Maximum size of the memory stream before swapping to file
|
@param ABufSize Maximum size of the memory stream before swapping to file
|
||||||
starts. Value is given in bytes.
|
starts. Value is given in bytes.
|
||||||
}
|
}
|
||||||
constructor TBufStream.Create(ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE);
|
constructor TBufStream.Create(ABufSize: Cardinal = Cardinal(-1));
|
||||||
begin
|
begin
|
||||||
Create('', false, ABufSize);
|
Create('', false, ABufSize);
|
||||||
end;
|
end;
|
||||||
@@ -103,9 +109,12 @@ end;
|
|||||||
starts. Value is given in bytes.
|
starts. Value is given in bytes.
|
||||||
}
|
}
|
||||||
constructor TBufStream.Create(AFileName: String; AMode: Word;
|
constructor TBufStream.Create(AFileName: String; AMode: Word;
|
||||||
ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE);
|
ABufSize: Cardinal = Cardinal(-1));
|
||||||
|
var
|
||||||
|
keep: Boolean;
|
||||||
begin
|
begin
|
||||||
Create(AFileName, true, ABufSize);
|
keep := AMode and (fmCreate + fmOpenWrite) <> 0;
|
||||||
|
Create(AFileName, keep, ABufSize);
|
||||||
FFileMode := AMode;
|
FFileMode := AMode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -117,7 +126,8 @@ begin
|
|||||||
// Free streams and delete temporary file, if requested
|
// Free streams and delete temporary file, if requested
|
||||||
FreeAndNil(FMemoryStream);
|
FreeAndNil(FMemoryStream);
|
||||||
FreeAndNil(FFileStream);
|
FreeAndNil(FFileStream);
|
||||||
if not FKeepTmpFile and (FFileName <> '') then DeleteFile(FFileName);
|
if not FKeepTmpFile and (FFileName <> '') and IsWritingMode then
|
||||||
|
DeleteFile(FFileName);
|
||||||
|
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
@@ -133,10 +143,25 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Reads FBufSize bytes from the stream into the buffer }
|
||||||
|
procedure TBufStream.FillBuffer;
|
||||||
|
var
|
||||||
|
p, n: Int64;
|
||||||
|
begin
|
||||||
|
p := GetPosition;
|
||||||
|
FMemoryStream.Clear;
|
||||||
|
FMemoryStream.Position := 0;
|
||||||
|
FFileStream.Position := p;
|
||||||
|
n := Min(FBufSize, FFileStream.Size - p);
|
||||||
|
FMemoryStream.CopyFrom(FFileStream, n);
|
||||||
|
FMemoryStream.Position := 0;
|
||||||
|
FFileStream.Position := p;
|
||||||
|
end;
|
||||||
|
|
||||||
{ Flushes the contents of the memory stream to file }
|
{ Flushes the contents of the memory stream to file }
|
||||||
procedure TBufStream.FlushBuffer;
|
procedure TBufStream.FlushBuffer;
|
||||||
begin
|
begin
|
||||||
if (FMemoryStream.Size > 0) and not FBufWritten then begin
|
if (FMemoryStream.Size > 0) and not FBufWritten and IsWritingMode then begin
|
||||||
FMemoryStream.Position := 0;
|
FMemoryStream.Position := 0;
|
||||||
CreateFileStream;
|
CreateFileStream;
|
||||||
FFileStream.CopyFrom(FMemoryStream, FMemoryStream.Size);
|
FFileStream.CopyFrom(FMemoryStream, FMemoryStream.Size);
|
||||||
@@ -161,12 +186,32 @@ function TBufStream.GetSize: Int64;
|
|||||||
var
|
var
|
||||||
n: Int64;
|
n: Int64;
|
||||||
begin
|
begin
|
||||||
|
if IsWritingMode then begin
|
||||||
if FFileStream <> nil then
|
if FFileStream <> nil then
|
||||||
n := FFileStream.Size
|
n := FFileStream.Size
|
||||||
else
|
else
|
||||||
n := 0;
|
n := 0;
|
||||||
if n = 0 then n := FMemoryStream.Size;
|
if n = 0 then n := FMemoryStream.Size;
|
||||||
Result := Max(n, GetPosition);
|
Result := Max(n, GetPosition);
|
||||||
|
end else begin
|
||||||
|
CreateFileStream;
|
||||||
|
Result := FFileStream.Size;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Returns true if the stream is in WritingMode.
|
||||||
|
"WritingMode" means that the stream is primarily used for writing. The
|
||||||
|
memory stream is initially empty but fills during writing, it is written to
|
||||||
|
disk when it is full.
|
||||||
|
The (unnamend) opposite of "WritingMode" indicates that the stream is used
|
||||||
|
for reading. The memory stream is initially full, but the stream pointer is at
|
||||||
|
it start. When data are read the stream pointer advances towards the end.
|
||||||
|
When the requested data are not contained in the memory stream another
|
||||||
|
ABufSize of bytes are read into the memory stream. }
|
||||||
|
function TBufStream.IsWritingMode: Boolean;
|
||||||
|
begin
|
||||||
|
Result := FFileMode and (fmCreate + fmOpenWrite) <> 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@@ -180,28 +225,39 @@ end;
|
|||||||
@return Number of bytes that were read from the stream.}
|
@return Number of bytes that were read from the stream.}
|
||||||
function TBufStream.Read(var Buffer; Count: Longint): Longint;
|
function TBufStream.Read(var Buffer; Count: Longint): Longint;
|
||||||
begin
|
begin
|
||||||
// Case 1: All "Count" bytes are contained in memory stream
|
// Case 1: Memory stream is empty
|
||||||
|
if FMemoryStream.Size = 0 then begin
|
||||||
|
CreateFileStream;
|
||||||
|
if IsWritingMode then begin
|
||||||
|
Result := FFileStream.Read(Buffer, Count);
|
||||||
|
end else begin
|
||||||
|
FillBuffer;
|
||||||
|
Result := FMemoryStream.Read(Buffer, Count);
|
||||||
|
end;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Case 2: All "Count" bytes are contained in memory stream
|
||||||
if FMemoryStream.Position + Count <= FMemoryStream.Size then begin
|
if FMemoryStream.Position + Count <= FMemoryStream.Size then begin
|
||||||
Result := FMemoryStream.Read(Buffer, Count);
|
Result := FMemoryStream.Read(Buffer, Count);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Case 2: Memory stream is empty
|
|
||||||
if FMemoryStream.Size = 0 then begin
|
|
||||||
CreateFileStream;
|
|
||||||
Result := FFileStream.Read(Buffer, Count);
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Case 3: Memory stream is not empty but contains only part of the bytes requested
|
// Case 3: Memory stream is not empty but contains only part of the bytes requested
|
||||||
|
if IsWritingMode then begin
|
||||||
FlushBuffer;
|
FlushBuffer;
|
||||||
Result := FFileStream.Read(Buffer, Count);
|
Result := FFileStream.Read(Buffer, Count);
|
||||||
|
end else begin
|
||||||
|
FillBuffer;
|
||||||
|
Result := FMemoryStream.Read(Buffer, Count);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TBufStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
|
function TBufStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
|
||||||
var
|
var
|
||||||
oldPos: Int64;
|
oldPos: Int64;
|
||||||
newPos: Int64;
|
newPos: Int64;
|
||||||
|
n: Int64;
|
||||||
begin
|
begin
|
||||||
oldPos := GetPosition;
|
oldPos := GetPosition;
|
||||||
case Origin of
|
case Origin of
|
||||||
@@ -226,8 +282,20 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// case #3: New position is outside buffer
|
// case #3: New position is outside buffer
|
||||||
|
if IsWritingMode then
|
||||||
FlushBuffer;
|
FlushBuffer;
|
||||||
FFileStream.Position := newPos;
|
FFileStream.Position := newPos;
|
||||||
|
FMemoryStream.Position := 0;
|
||||||
|
if not IsWritingMode then begin
|
||||||
|
FillBuffer;
|
||||||
|
{
|
||||||
|
FMemoryStream.Position := 0;
|
||||||
|
n := Min(FBufSize, FFileStream.Size - newPos);
|
||||||
|
FMemoryStream.CopyFrom(FFileStream, n);
|
||||||
|
FFileStream.Position := newPos;
|
||||||
|
FMemoryStream.Position := 0;
|
||||||
|
}
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TBufStream.Write(const ABuffer; ACount: LongInt): LongInt;
|
function TBufStream.Write(const ABuffer; ACount: LongInt): LongInt;
|
||||||
|
@@ -51,6 +51,7 @@ type
|
|||||||
// Write out date cell and try to read as UTF8; verify if contents the same
|
// Write out date cell and try to read as UTF8; verify if contents the same
|
||||||
procedure ReadDateAsUTF8;
|
procedure ReadDateAsUTF8;
|
||||||
// Test buffered stream
|
// Test buffered stream
|
||||||
|
procedure TestReadBufStream;
|
||||||
procedure TestBufStream;
|
procedure TestBufStream;
|
||||||
|
|
||||||
// Virtual mode tests for all file formats
|
// Virtual mode tests for all file formats
|
||||||
@@ -252,6 +253,95 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadInternalTests.TestReadBufStream;
|
||||||
|
const
|
||||||
|
BUF_SIZE = 1024;
|
||||||
|
FILE_SIZE = 2000;
|
||||||
|
var
|
||||||
|
tempFileName: String;
|
||||||
|
stream: TStream;
|
||||||
|
writedata: array of Byte;
|
||||||
|
readdata: array of Byte;
|
||||||
|
i, n, nread: Integer;
|
||||||
|
begin
|
||||||
|
RandSeed := 0;
|
||||||
|
|
||||||
|
// Create a test file
|
||||||
|
tempFileName := GetTempFileName;
|
||||||
|
stream := TFileStream.Create(tempFileName, fmCreate);
|
||||||
|
try
|
||||||
|
SetLength(writedata, FILE_SIZE);
|
||||||
|
for i:=0 to High(writedata) do
|
||||||
|
writedata[i] := random(256);
|
||||||
|
stream.WriteBuffer(writedata[0], Length(writedata));
|
||||||
|
finally
|
||||||
|
stream.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use a TBufStream to read parts of the file back
|
||||||
|
stream := TBufStream.Create(tempFilename, fmOpenRead, BUF_SIZE);
|
||||||
|
try
|
||||||
|
// Check stream size
|
||||||
|
CheckEquals(FILE_SIZE, stream.Size, 'Size mismatch');
|
||||||
|
|
||||||
|
// Read first 100 bytes and compare with data
|
||||||
|
nread := 100;
|
||||||
|
SetLength(readdata, nread);
|
||||||
|
n := stream.Read(readdata[0], nread);
|
||||||
|
CheckEquals(nread, n, 'Bytes count mismatch');
|
||||||
|
for i:=0 to nread-1 do
|
||||||
|
CheckEquals(writedata[i], readdata[i], Format('Read mismatch at position %d', [i]));
|
||||||
|
|
||||||
|
// Check stream size
|
||||||
|
CheckEquals(FILE_SIZE, stream.Size, 'Size mismatch');
|
||||||
|
|
||||||
|
// Read next 100 bytes and compare
|
||||||
|
stream.ReadBuffer(readdata[0], nread);
|
||||||
|
for i:=0 to nread-1 do
|
||||||
|
CheckEquals(writedata[i+nread], readdata[i], Format('Read mismatch at position %d', [i+nread]));
|
||||||
|
|
||||||
|
// Go to position 1000, this is 24 bytes to the end of the buffer, and read
|
||||||
|
// 100 bytes again - this process will require to refresh the buffer
|
||||||
|
stream.Position := 1000;
|
||||||
|
stream.ReadBuffer(readdata[0], nread);
|
||||||
|
for i:=0 to nread-1 do
|
||||||
|
CheckEquals(writedata[i+1000], readdata[i], Format('Read mismatch at position %d', [i+1000]));
|
||||||
|
|
||||||
|
// Check stream size
|
||||||
|
CheckEquals(FILE_SIZE, stream.Size, 'Size mismatch');
|
||||||
|
|
||||||
|
// Read next 100 bytes
|
||||||
|
stream.ReadBuffer(readdata[0], nread);
|
||||||
|
for i:=0 to nread-1 do
|
||||||
|
CheckEquals(writedata[i+1000+nread], readdata[i], Format('Read mismatch at position %d', [i+1000+nread]));
|
||||||
|
|
||||||
|
// Go back to start and fill the memory stream again with bytes 0..1023
|
||||||
|
stream.Position := 0;
|
||||||
|
stream.ReadBuffer(readdata[0], nread);
|
||||||
|
|
||||||
|
// Now read 100 bytes which are not in the buffer
|
||||||
|
stream.Position := 1500; // this is past the buffered range
|
||||||
|
stream.ReadBuffer(readdata[0], 100);
|
||||||
|
for i:=0 to nread-1 do
|
||||||
|
CheckEquals(writedata[i+1500], readdata[i], Format('Read mismatch at position %d', [i+1500]));
|
||||||
|
|
||||||
|
// Go back to start and fill the memory stream again with bytes 0..1023
|
||||||
|
stream.Position := 0;
|
||||||
|
stream.ReadBuffer(readdata[0], 100);
|
||||||
|
|
||||||
|
// Read last 100 bytes
|
||||||
|
stream.Seek(nread, soFromEnd);
|
||||||
|
stream.ReadBuffer(readdata[0], nread);
|
||||||
|
for i:=0 to nread-1 do
|
||||||
|
CheckEquals(writedata[i+FILE_SIZE-nread], readdata[i],
|
||||||
|
Format('Read mismatch at position %d', [i+FILE_SIZE-nread]));
|
||||||
|
|
||||||
|
finally
|
||||||
|
stream.Free;
|
||||||
|
DeleteFile(tempFileName);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSpreadInternalTests.TestCellString;
|
procedure TSpreadInternalTests.TestCellString;
|
||||||
var
|
var
|
||||||
r,c: Cardinal;
|
r,c: Cardinal;
|
||||||
@@ -307,9 +397,9 @@ begin
|
|||||||
workbook := TsWorkbook.Create;
|
workbook := TsWorkbook.Create;
|
||||||
try
|
try
|
||||||
worksheet := workbook.AddWorksheet('VirtualMode');
|
worksheet := workbook.AddWorksheet('VirtualMode');
|
||||||
workbook.WritingOptions := workbook.WritingOptions + [woVirtualMode];
|
workbook.Options := workbook.Options + [boVirtualMode];
|
||||||
if ABufStreamMode then
|
if ABufStreamMode then
|
||||||
workbook.WritingOptions := workbook.WritingOptions + [woBufStream];
|
workbook.Options := workbook.Options + [boBufStream];
|
||||||
workbook.VirtualColCount := 1;
|
workbook.VirtualColCount := 1;
|
||||||
workbook.VirtualRowCount := Length(SollNumbers) + 4;
|
workbook.VirtualRowCount := Length(SollNumbers) + 4;
|
||||||
// We'll use only the first 4 SollStrings, the others cause trouble due to utf8 and formatting.
|
// We'll use only the first 4 SollStrings, the others cause trouble due to utf8 and formatting.
|
||||||
|
@@ -1084,7 +1084,7 @@ begin
|
|||||||
WriteColWidths(AStream);
|
WriteColWidths(AStream);
|
||||||
WriteRows(AStream, sheet);
|
WriteRows(AStream, sheet);
|
||||||
|
|
||||||
if (woVirtualMode in Workbook.WritingOptions) then
|
if (boVirtualMode in Workbook.Options) then
|
||||||
WriteVirtualCells(AStream)
|
WriteVirtualCells(AStream)
|
||||||
else begin
|
else begin
|
||||||
WriteRows(AStream, sheet);
|
WriteRows(AStream, sheet);
|
||||||
|
@@ -347,7 +347,7 @@ var
|
|||||||
OutputStorage: TOLEStorage;
|
OutputStorage: TOLEStorage;
|
||||||
OLEDocument: TOLEDocument;
|
OLEDocument: TOLEDocument;
|
||||||
begin
|
begin
|
||||||
if (woBufStream in Workbook.WritingOptions) then begin
|
if (boBufStream in Workbook.Options) then begin
|
||||||
Stream := TBufStream.Create
|
Stream := TBufStream.Create
|
||||||
end else
|
end else
|
||||||
Stream := TMemoryStream.Create;
|
Stream := TMemoryStream.Create;
|
||||||
@@ -434,7 +434,7 @@ begin
|
|||||||
WriteSelection(AStream, sheet, pane);
|
WriteSelection(AStream, sheet, pane);
|
||||||
WriteRows(AStream, sheet);
|
WriteRows(AStream, sheet);
|
||||||
|
|
||||||
if (woVirtualMode in Workbook.WritingOptions) then
|
if (boVirtualMode in Workbook.Options) then
|
||||||
WriteVirtualCells(AStream)
|
WriteVirtualCells(AStream)
|
||||||
else begin
|
else begin
|
||||||
WriteRows(AStream, sheet);
|
WriteRows(AStream, sheet);
|
||||||
|
@@ -365,7 +365,7 @@ var
|
|||||||
OutputStorage: TOLEStorage;
|
OutputStorage: TOLEStorage;
|
||||||
OLEDocument: TOLEDocument;
|
OLEDocument: TOLEDocument;
|
||||||
begin
|
begin
|
||||||
if (woBufStream in Workbook.WritingOptions) then begin
|
if (boBufStream in Workbook.Options) then begin
|
||||||
Stream := TBufStream.Create
|
Stream := TBufStream.Create
|
||||||
end else
|
end else
|
||||||
Stream := TMemoryStream.Create;
|
Stream := TMemoryStream.Create;
|
||||||
@@ -446,7 +446,7 @@ begin
|
|||||||
WriteDimensions(AStream, sheet);
|
WriteDimensions(AStream, sheet);
|
||||||
//WriteRowAndCellBlock(AStream, sheet);
|
//WriteRowAndCellBlock(AStream, sheet);
|
||||||
|
|
||||||
if (woVirtualMode in Workbook.WritingOptions) then
|
if (boVirtualMode in Workbook.Options) then
|
||||||
WriteVirtualCells(AStream)
|
WriteVirtualCells(AStream)
|
||||||
else begin
|
else begin
|
||||||
WriteRows(AStream, sheet);
|
WriteRows(AStream, sheet);
|
||||||
|
@@ -880,7 +880,7 @@ begin
|
|||||||
h0 := Workbook.GetDefaultFontSize; // Point size of default font
|
h0 := Workbook.GetDefaultFontSize; // Point size of default font
|
||||||
|
|
||||||
// Create the stream
|
// Create the stream
|
||||||
if (woBufStream in Workbook.WritingOptions) then
|
if (boBufStream in Workbook.Options) then
|
||||||
FSSheets[FCurSheetNum] := TBufStream.Create(GetTempFileName('', Format('fpsSH%d', [FCurSheetNum])))
|
FSSheets[FCurSheetNum] := TBufStream.Create(GetTempFileName('', Format('fpsSH%d', [FCurSheetNum])))
|
||||||
else
|
else
|
||||||
FSSheets[FCurSheetNum] := TMemoryStream.Create;
|
FSSheets[FCurSheetNum] := TMemoryStream.Create;
|
||||||
@@ -902,7 +902,7 @@ begin
|
|||||||
AppendToStream(FSSheets[FCurSheetNum],
|
AppendToStream(FSSheets[FCurSheetNum],
|
||||||
'<sheetData>');
|
'<sheetData>');
|
||||||
|
|
||||||
if (woVirtualMode in Workbook.WritingOptions) and Assigned(Workbook.OnNeedCellData)
|
if (boVirtualMode in Workbook.Options) and Assigned(Workbook.OnNeedCellData)
|
||||||
then begin
|
then begin
|
||||||
for r := 0 to Workbook.VirtualRowCount-1 do begin
|
for r := 0 to Workbook.VirtualRowCount-1 do begin
|
||||||
row := CurSheet.FindRow(r);
|
row := CurSheet.FindRow(r);
|
||||||
@@ -1012,7 +1012,7 @@ end;
|
|||||||
single xlsx file. }
|
single xlsx file. }
|
||||||
procedure TsSpreadOOXMLWriter.CreateStreams;
|
procedure TsSpreadOOXMLWriter.CreateStreams;
|
||||||
begin
|
begin
|
||||||
if (woBufStream in Workbook.WritingOptions) then begin
|
if (boBufStream in Workbook.Options) then begin
|
||||||
FSContentTypes := TBufStream.Create(GetTempFileName('', 'fpsCT'));
|
FSContentTypes := TBufStream.Create(GetTempFileName('', 'fpsCT'));
|
||||||
FSRelsRels := TBufStream.Create(GetTempFileName('', 'fpsRR'));
|
FSRelsRels := TBufStream.Create(GetTempFileName('', 'fpsRR'));
|
||||||
FSWorkbookRels := TBufStream.Create(GetTempFileName('', 'fpsWBR'));
|
FSWorkbookRels := TBufStream.Create(GetTempFileName('', 'fpsWBR'));
|
||||||
@@ -1111,7 +1111,7 @@ begin
|
|||||||
then lMode := fmCreate or fmOpenWrite
|
then lMode := fmCreate or fmOpenWrite
|
||||||
else lMode := fmCreate;
|
else lMode := fmCreate;
|
||||||
|
|
||||||
if (woBufStream in Workbook.WritingOptions) then
|
if (boBufStream in Workbook.Options) then
|
||||||
lStream := TBufStream.Create(AFileName, lMode)
|
lStream := TBufStream.Create(AFileName, lMode)
|
||||||
else
|
else
|
||||||
lStream := TFileStream.Create(AFileName, lMode);
|
lStream := TFileStream.Create(AFileName, lMode);
|
||||||
|
Reference in New Issue
Block a user