You've already forked lazarus-ccr
fpspreadsheet: Use TBufStream as general-purpose stream if woBufStream is set in Worksheet.WritingOptions. woBufStream replaces woSaveMemory. Results in a significant speed enhancement for biff2 (64000x100 cells -> 31 sec without, 1.7 sec with woBufStream).
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3337 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -65,11 +65,12 @@ begin
|
|||||||
|
|
||||||
{ These are the essential commands to activate virtual mode: }
|
{ These are the essential commands to activate virtual mode: }
|
||||||
|
|
||||||
// workbook.WritingOptions := [woVirtualMode, woSaveMemory];
|
workbook.WritingOptions := [woVirtualMode, woBufStream];
|
||||||
workbook.WritingOptions := [woVirtualMode];
|
// workbook.WritingOptions := [woVirtualMode];
|
||||||
{ woSaveMemory can be omitted, but is essential for large files: it causes
|
{ woBufStream can be omitted, but is important for large files: it causes
|
||||||
writing temporaray data to a file stream instead of a memory stream.
|
writing temporary data to a buffered file stream instead of a pure
|
||||||
woSaveMemory, however, considerably slows down writing of biff files. }
|
memory stream which can overflow memory. The option can slow 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
|
||||||
|
@ -2239,7 +2239,7 @@ procedure TsSpreadOpenDocWriter.CreateStreams;
|
|||||||
var
|
var
|
||||||
dir: String;
|
dir: String;
|
||||||
begin
|
begin
|
||||||
if (woSaveMemory in Workbook.WritingOptions) then begin
|
if (woBufStream in Workbook.WritingOptions) then begin
|
||||||
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);
|
||||||
|
@ -704,10 +704,9 @@ type
|
|||||||
@param woVirtualMode If in virtual mode date are not taken from cells
|
@param woVirtualMode 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 woSaveMemory When this option is set temporary files are not
|
@param woBufStream When this option is set a buffered stream is used
|
||||||
written to memory streams but to file streams using
|
for writing (a memory stream swapping to disk) }
|
||||||
temporary files. }
|
TsWorkbookWritingOption = (woVirtualMode, woBufStream);
|
||||||
TsWorkbookWritingOption = (woVirtualMode, woSaveMemory);
|
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Options considered when writing a workbook }
|
Options considered when writing a workbook }
|
||||||
@ -1076,7 +1075,7 @@ function SameCellBorders(ACell1, ACell2: PCell): Boolean;
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Math, StrUtils, TypInfo, fpsUtils, fpsNumFormatParser, fpsFunc;
|
Math, StrUtils, TypInfo, fpsStreams, fpsUtils, fpsNumFormatParser, fpsFunc;
|
||||||
|
|
||||||
{ Translatable strings }
|
{ Translatable strings }
|
||||||
resourcestring
|
resourcestring
|
||||||
@ -5702,13 +5701,16 @@ end;
|
|||||||
procedure TsCustomSpreadWriter.WriteToFile(const AFileName: string;
|
procedure TsCustomSpreadWriter.WriteToFile(const AFileName: string;
|
||||||
const AOverwriteExisting: Boolean = False);
|
const AOverwriteExisting: Boolean = False);
|
||||||
var
|
var
|
||||||
OutputFile: TFileStream;
|
OutputFile: TStream;
|
||||||
lMode: Word;
|
lMode: Word;
|
||||||
begin
|
begin
|
||||||
if AOverwriteExisting then lMode := fmCreate or fmOpenWrite
|
if AOverwriteExisting then lMode := fmCreate or fmOpenWrite
|
||||||
else lMode := fmCreate;
|
else lMode := fmCreate;
|
||||||
|
|
||||||
OutputFile := TFileStream.Create(AFileName, lMode);
|
if (woBufStream in Workbook.WritingOptions) then
|
||||||
|
OutputFile := TBufStream.Create(AFileName, lMode)
|
||||||
|
else
|
||||||
|
OutputFile := TFileStream.Create(AFileName, lMode);
|
||||||
try
|
try
|
||||||
WriteToStream(OutputFile);
|
WriteToStream(OutputFile);
|
||||||
finally
|
finally
|
||||||
|
@ -6,7 +6,7 @@ uses
|
|||||||
SysUtils, Classes;
|
SysUtils, Classes;
|
||||||
|
|
||||||
const
|
const
|
||||||
DEFAULT_STREAM_BUFFER_SIZE = 1024; // * 1024;
|
DEFAULT_STREAM_BUFFER_SIZE = 1024 * 1024;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ A buffered stream }
|
{ A buffered stream }
|
||||||
@ -18,11 +18,14 @@ type
|
|||||||
FBufSize: Int64;
|
FBufSize: Int64;
|
||||||
FKeepTmpFile: Boolean;
|
FKeepTmpFile: Boolean;
|
||||||
FFileName: String;
|
FFileName: String;
|
||||||
|
FFileMode: Word;
|
||||||
protected
|
protected
|
||||||
procedure CreateFileStream;
|
procedure CreateFileStream;
|
||||||
function GetPosition: Int64; override;
|
function GetPosition: Int64; override;
|
||||||
function GetSize: Int64; override;
|
function GetSize: Int64; override;
|
||||||
public
|
public
|
||||||
|
constructor Create(AFileName: String; AMode: Word;
|
||||||
|
ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE); overload;
|
||||||
constructor Create(ATempFile: String; AKeepFile: Boolean = false;
|
constructor Create(ATempFile: String; AKeepFile: Boolean = false;
|
||||||
ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE); overload;
|
ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE); overload;
|
||||||
constructor Create(ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE); overload;
|
constructor Create(ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE); overload;
|
||||||
@ -46,7 +49,18 @@ begin
|
|||||||
AStream.Position := 0;
|
AStream.Position := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Constructor of the TBufStream. Creates a memory stream and prepares everything
|
||||||
|
to create also a file stream if the streamsize exceeds ABufSize bytes.
|
||||||
|
|
||||||
|
@param ATempFile File name for the file stream. If an empty string is
|
||||||
|
used a temporary file name is created by calling GetTempFileName.
|
||||||
|
@param AKeepFile If true the stream is flushed to file when the stream is
|
||||||
|
destroyed. If false the file is deleted when the stream
|
||||||
|
is destroyed.
|
||||||
|
@param ABufSize Maximum size of the memory stream before swapping to file
|
||||||
|
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 = DEFAULT_STREAM_BUFFER_SIZE);
|
||||||
begin
|
begin
|
||||||
@ -60,17 +74,45 @@ begin
|
|||||||
// 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.
|
||||||
FBufSize := ABufSize;
|
FBufSize := ABufSize;
|
||||||
|
FFileMode := fmCreate + fmOpenRead;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Constructor of the TBufStream. Creates a memory stream and prepares everything
|
||||||
|
to create also a file stream if the streamsize exceeds ABufSize bytes. The
|
||||||
|
stream created by this constructor is mainly intended to serve a temporary
|
||||||
|
purpose, it is not stored permanently to file.
|
||||||
|
|
||||||
|
@param ABufSize Maximum size of the memory stream before swapping to file
|
||||||
|
starts. Value is given in bytes.
|
||||||
|
}
|
||||||
constructor TBufStream.Create(ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE);
|
constructor TBufStream.Create(ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE);
|
||||||
begin
|
begin
|
||||||
Create('', false, ABufSize);
|
Create('', false, ABufSize);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Constructor of the TBufStream. When swapping to file it will create a file
|
||||||
|
stream using the given file mode. This kind of BufStream is considered as a
|
||||||
|
fast replacement of TFileStream.
|
||||||
|
|
||||||
|
@param AFileName File name for the file stream. If an empty string is
|
||||||
|
used a temporary file name is created by calling GetTempFileName.
|
||||||
|
@param AMode FileMode for the file stream (fmCreate, fmOpenRead etc.)
|
||||||
|
@param ABufSize Maximum size of the memory stream before swapping to file
|
||||||
|
starts. Value is given in bytes.
|
||||||
|
}
|
||||||
|
constructor TBufStream.Create(AFileName: String; AMode: Word;
|
||||||
|
ABufSize: Cardinal = DEFAULT_STREAM_BUFFER_SIZE);
|
||||||
|
begin
|
||||||
|
Create(AFileName, true, ABufSize);
|
||||||
|
FFileMode := AMode;
|
||||||
|
end;
|
||||||
|
|
||||||
destructor TBufStream.Destroy;
|
destructor TBufStream.Destroy;
|
||||||
begin
|
begin
|
||||||
// Write current buffer content to file
|
// Write current buffer content to file
|
||||||
FlushBuffer;
|
if FKeepTmpFile then FlushBuffer;
|
||||||
|
|
||||||
// Free streams and delete temporary file, if requested
|
// Free streams and delete temporary file, if requested
|
||||||
FreeAndNil(FMemoryStream);
|
FreeAndNil(FMemoryStream);
|
||||||
@ -87,7 +129,7 @@ procedure TBufStream.CreateFileStream;
|
|||||||
begin
|
begin
|
||||||
if FFileStream = nil then begin
|
if FFileStream = nil then begin
|
||||||
if FFileName = '' then FFileName := ChangeFileExt(GetTempFileName, '.~abc');
|
if FFileName = '' then FFileName := ChangeFileExt(GetTempFileName, '.~abc');
|
||||||
FFileStream := TFileStream.Create(FFileName, fmCreate + fmOpenRead);
|
FFileStream := TFileStream.Create(FFileName, FFileMode);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -113,6 +155,8 @@ begin
|
|||||||
Result := FFileStream.Position + FMemoryStream.Position;
|
Result := FFileStream.Position + FMemoryStream.Position;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Returns the size of the stream. Both memory and file streams are considered
|
||||||
|
if needed. }
|
||||||
function TBufStream.GetSize: Int64;
|
function TBufStream.GetSize: Int64;
|
||||||
var
|
var
|
||||||
n: Int64;
|
n: Int64;
|
||||||
@ -125,6 +169,15 @@ begin
|
|||||||
Result := Max(n, GetPosition);
|
Result := Max(n, GetPosition);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Reads a given number of bytes into a buffer and return the number of bytes
|
||||||
|
read. If the bytes are not in the memory stream they are read from the file
|
||||||
|
stream.
|
||||||
|
|
||||||
|
@param Buffer Buffer into which the bytes are read. Sufficient space must
|
||||||
|
have been allocated for Count bytes
|
||||||
|
@param Count Number of bytes to 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: All "Count" bytes are contained in memory stream
|
||||||
|
@ -34,7 +34,7 @@ type
|
|||||||
// Set up expected values:
|
// Set up expected values:
|
||||||
procedure SetUp; override;
|
procedure SetUp; override;
|
||||||
procedure TearDown; override;
|
procedure TearDown; override;
|
||||||
procedure TestVirtualMode(AFormat: TsSpreadsheetFormat; SaveMemoryMode: Boolean);
|
procedure TestVirtualMode(AFormat: TsSpreadsheetFormat; ABufStreamMode: Boolean);
|
||||||
|
|
||||||
published
|
published
|
||||||
// Tests getting Excel style A1 cell locations from row/column based locations.
|
// Tests getting Excel style A1 cell locations from row/column based locations.
|
||||||
@ -59,10 +59,10 @@ type
|
|||||||
procedure TestVirtualMode_BIFF8;
|
procedure TestVirtualMode_BIFF8;
|
||||||
procedure TestVirtualMode_OOXML;
|
procedure TestVirtualMode_OOXML;
|
||||||
|
|
||||||
procedure TestVirtualMode_BIFF2_SaveMemory;
|
procedure TestVirtualMode_BIFF2_BufStream;
|
||||||
procedure TestVirtualMode_BIFF5_SaveMemory;
|
procedure TestVirtualMode_BIFF5_BufStream;
|
||||||
procedure TestVirtualMode_BIFF8_SaveMemory;
|
procedure TestVirtualMode_BIFF8_BufStream;
|
||||||
procedure TestVirtualMode_OOXML_SaveMemory;
|
procedure TestVirtualMode_OOXML_BufStream;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -295,7 +295,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadInternalTests.TestVirtualMode(AFormat: TsSpreadsheetFormat;
|
procedure TSpreadInternalTests.TestVirtualMode(AFormat: TsSpreadsheetFormat;
|
||||||
SaveMemoryMode: Boolean);
|
ABufStreamMode: Boolean);
|
||||||
var
|
var
|
||||||
tempFile: String;
|
tempFile: String;
|
||||||
workbook: TsWorkbook;
|
workbook: TsWorkbook;
|
||||||
@ -308,8 +308,8 @@ begin
|
|||||||
try
|
try
|
||||||
worksheet := workbook.AddWorksheet('VirtualMode');
|
worksheet := workbook.AddWorksheet('VirtualMode');
|
||||||
workbook.WritingOptions := workbook.WritingOptions + [woVirtualMode];
|
workbook.WritingOptions := workbook.WritingOptions + [woVirtualMode];
|
||||||
if SaveMemoryMode then
|
if ABufStreamMode then
|
||||||
workbook.WritingOptions := workbook.WritingOptions + [woSaveMemory];
|
workbook.WritingOptions := workbook.WritingOptions + [woBufStream];
|
||||||
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.
|
||||||
@ -368,22 +368,22 @@ begin
|
|||||||
TestVirtualMode(sfOOXML, false);
|
TestVirtualMode(sfOOXML, false);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadInternalTests.TestVirtualMode_BIFF2_SaveMemory;
|
procedure TSpreadInternalTests.TestVirtualMode_BIFF2_BufStream;
|
||||||
begin
|
begin
|
||||||
TestVirtualMode(sfExcel2, True);
|
TestVirtualMode(sfExcel2, True);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadInternalTests.TestVirtualMode_BIFF5_SaveMemory;
|
procedure TSpreadInternalTests.TestVirtualMode_BIFF5_BufStream;
|
||||||
begin
|
begin
|
||||||
TestVirtualMode(sfExcel5, true);
|
TestVirtualMode(sfExcel5, true);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadInternalTests.TestVirtualMode_BIFF8_SaveMemory;
|
procedure TSpreadInternalTests.TestVirtualMode_BIFF8_BufStream;
|
||||||
begin
|
begin
|
||||||
TestVirtualMode(sfExcel8, true);
|
TestVirtualMode(sfExcel8, true);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadInternalTests.TestVirtualMode_OOXML_SaveMemory;
|
procedure TSpreadInternalTests.TestVirtualMode_OOXML_BufStream;
|
||||||
begin
|
begin
|
||||||
TestVirtualMode(sfOOXML, true);
|
TestVirtualMode(sfOOXML, true);
|
||||||
end;
|
end;
|
||||||
|
@ -219,6 +219,9 @@ var
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
fpsStreams;
|
||||||
|
|
||||||
const
|
const
|
||||||
{ Excel record IDs }
|
{ Excel record IDs }
|
||||||
// see: in xlscommon
|
// see: in xlscommon
|
||||||
@ -330,21 +333,25 @@ end;
|
|||||||
procedure TsSpreadBIFF5Writer.WriteToFile(const AFileName: string;
|
procedure TsSpreadBIFF5Writer.WriteToFile(const AFileName: string;
|
||||||
const AOverwriteExisting: Boolean);
|
const AOverwriteExisting: Boolean);
|
||||||
var
|
var
|
||||||
MemStream: TMemoryStream;
|
Stream: TStream;
|
||||||
OutputStorage: TOLEStorage;
|
OutputStorage: TOLEStorage;
|
||||||
OLEDocument: TOLEDocument;
|
OLEDocument: TOLEDocument;
|
||||||
begin
|
begin
|
||||||
MemStream := TMemoryStream.Create;
|
if (woBufStream in Workbook.WritingOptions) then begin
|
||||||
|
Stream := TBufStream.Create
|
||||||
|
end else
|
||||||
|
Stream := TMemoryStream.Create;
|
||||||
|
|
||||||
OutputStorage := TOLEStorage.Create;
|
OutputStorage := TOLEStorage.Create;
|
||||||
try
|
try
|
||||||
WriteToStream(MemStream);
|
WriteToStream(Stream);
|
||||||
|
|
||||||
// Only one stream is necessary for any number of worksheets
|
// Only one stream is necessary for any number of worksheets
|
||||||
OLEDocument.Stream := MemStream;
|
OLEDocument.Stream := Stream;
|
||||||
|
|
||||||
OutputStorage.WriteOLEFile(AFileName, OLEDocument, AOverwriteExisting);
|
OutputStorage.WriteOLEFile(AFileName, OLEDocument, AOverwriteExisting);
|
||||||
finally
|
finally
|
||||||
MemStream.Free;
|
Stream.Free;
|
||||||
OutputStorage.Free;
|
OutputStorage.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -365,7 +365,7 @@ var
|
|||||||
OutputStorage: TOLEStorage;
|
OutputStorage: TOLEStorage;
|
||||||
OLEDocument: TOLEDocument;
|
OLEDocument: TOLEDocument;
|
||||||
begin
|
begin
|
||||||
if (woSaveMemory in Workbook.WritingOptions) then begin
|
if (woBufStream in Workbook.WritingOptions) then begin
|
||||||
Stream := TBufStream.Create
|
Stream := TBufStream.Create
|
||||||
end else
|
end else
|
||||||
Stream := TMemoryStream.Create;
|
Stream := TMemoryStream.Create;
|
||||||
|
@ -883,7 +883,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 (woSaveMemory in Workbook.WritingOptions) then
|
if (woBufStream in Workbook.WritingOptions) 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;
|
||||||
@ -1013,7 +1013,7 @@ end;
|
|||||||
single xlsx file. }
|
single xlsx file. }
|
||||||
procedure TsSpreadOOXMLWriter.CreateStreams;
|
procedure TsSpreadOOXMLWriter.CreateStreams;
|
||||||
begin
|
begin
|
||||||
if (woSaveMemory in Workbook.WritingOptions) then begin
|
if (woBufStream in Workbook.WritingOptions) 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'));
|
||||||
@ -1106,14 +1106,17 @@ end;
|
|||||||
procedure TsSpreadOOXMLWriter.WriteToFile(const AFileName: string;
|
procedure TsSpreadOOXMLWriter.WriteToFile(const AFileName: string;
|
||||||
const AOverwriteExisting: Boolean);
|
const AOverwriteExisting: Boolean);
|
||||||
var
|
var
|
||||||
lStream: TFileStream;
|
lStream: TStream;
|
||||||
lMode: word;
|
lMode: word;
|
||||||
begin
|
begin
|
||||||
if AOverwriteExisting
|
if AOverwriteExisting
|
||||||
then lMode := fmCreate or fmOpenWrite
|
then lMode := fmCreate or fmOpenWrite
|
||||||
else lMode := fmCreate;
|
else lMode := fmCreate;
|
||||||
|
|
||||||
lStream:=TFileStream.Create(AFileName, lMode);
|
if (woBufStream in Workbook.WritingOptions) then
|
||||||
|
lStream := TBufStream.Create(AFileName, lMode)
|
||||||
|
else
|
||||||
|
lStream := TFileStream.Create(AFileName, lMode);
|
||||||
try
|
try
|
||||||
WriteToStream(lStream);
|
WriteToStream(lStream);
|
||||||
finally
|
finally
|
||||||
@ -1139,7 +1142,7 @@ begin
|
|||||||
WriteGlobalFiles;
|
WriteGlobalFiles;
|
||||||
WriteContent;
|
WriteContent;
|
||||||
|
|
||||||
// Stream position must be at beginning, it was moved to end during adding of xml strings.
|
// Stream positions must be at beginning, they were moved to end during adding of xml strings.
|
||||||
ResetStreams;
|
ResetStreams;
|
||||||
|
|
||||||
{ Now compress the files }
|
{ Now compress the files }
|
||||||
|
Reference in New Issue
Block a user