fpspreadsheet: Fix buffered stream reading speed issues.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3904 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-01-27 19:31:57 +00:00
parent 2b0276dfbc
commit 8f3d5d471f
5 changed files with 47 additions and 20 deletions

View File

@ -10,7 +10,7 @@ program excel8write;
{$mode delphi}{$H+} {$mode delphi}{$H+}
uses uses
Classes, SysUtils, fpspreadsheet, fpsRPN, xlsbiff8, fpsTypes, fpsHelpers; Classes, SysUtils, fpspreadsheet, fpsRPN, xlsbiff8, fpsTypes, fpsCell;
const const
Str_First = 'First'; Str_First = 'First';

View File

@ -60,7 +60,6 @@
</Target> </Target>
<SearchPaths> <SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/> <IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="C:\Users\Rik\Downloads\udata\"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths> </SearchPaths>
<Parsing> <Parsing>

View File

@ -8447,10 +8447,18 @@ procedure TsCustomSpreadReader.ReadFromFile(AFileName: string; AData: TsWorkbook
var var
InputFile: TStream; InputFile: TStream;
begin begin
if (boBufStream in Workbook.Options) then if (boBufStream in Workbook.Options) then
InputFile := TBufStream.Create(AFileName, fmOpenRead + fmShareDenyNone) InputFile := TBufStream.Create(AFileName, fmOpenRead + fmShareDenyNone)
else else
InputFile := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyNone); InputFile := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyNone);
{
//<--
InputFile := TMemoryStream.Create;
TMemoryStream(InputFile).LoadFromFile(AFilename);
//--->
}
try try
ReadFromStream(InputFile, AData); ReadFromStream(InputFile, AData);
finally finally

View File

@ -18,6 +18,8 @@ type
private private
FFileStream: TFileStream; FFileStream: TFileStream;
FMemoryStream: TMemoryStream; FMemoryStream: TMemoryStream;
FFileStreamPos: Int64;
FFileStreamSize: Int64;
FBufWritten: Boolean; FBufWritten: Boolean;
FBufSize: Int64; FBufSize: Int64;
FKeepTmpFile: Boolean; FKeepTmpFile: Boolean;
@ -144,10 +146,13 @@ 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, FFileMode); FFileStream := TFileStream.Create(FFileName, FFileMode);
FFileStreamSize := FFileStream.Size;
FFileStreamPos := 0;
end; end;
end; end;
{ Reads FBufSize bytes from the stream into the buffer } { Reads FBufSize bytes from the stream into the buffer.
Called when reading. }
procedure TBufStream.FillBuffer; procedure TBufStream.FillBuffer;
var var
p, n: Int64; p, n: Int64;
@ -156,19 +161,23 @@ begin
FMemoryStream.Clear; FMemoryStream.Clear;
FMemoryStream.Position := 0; FMemoryStream.Position := 0;
FFileStream.Position := p; FFileStream.Position := p;
n := Min(FBufSize, FFileStream.Size - p); n := Min(FBufSize, FFileStreamSize - p);
FMemoryStream.CopyFrom(FFileStream, n); FMemoryStream.CopyFrom(FFileStream, n);
FMemoryStream.Position := 0; FMemoryStream.Position := 0;
FFileStream.Position := p; FFileStream.Position := p; // The file stream ends where the memorystream begins!
FFileStreamPos := p;
end; end;
{ Flushes the contents of the memory stream to file } { Flushes the contents of the memory stream to file
Called when writing. }
procedure TBufStream.FlushBuffer; procedure TBufStream.FlushBuffer;
begin begin
if (FMemoryStream.Size > 0) and not FBufWritten and IsWritingMode 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);
FFileStreamPos := FFileStream.Position;
FFileStreamSize := FFileStream.Size;
FMemoryStream.Clear; FMemoryStream.Clear;
FBufWritten := true; FBufWritten := true;
end; end;
@ -181,7 +190,8 @@ begin
if FFileStream = nil then if FFileStream = nil then
Result := FMemoryStream.Position Result := FMemoryStream.Position
else else
Result := FFileStream.Position + FMemoryStream.Position; // Result := FFileStream.Position + FMemoryStream.Position;
Result := FFileStreamPos + FMemoryStream.Position;
end; end;
{ Returns the size of the stream. Both memory and file streams are considered { Returns the size of the stream. Both memory and file streams are considered
@ -192,14 +202,15 @@ var
begin begin
if IsWritingMode then begin if IsWritingMode then begin
if FFileStream <> nil then if FFileStream <> nil then
n := FFileStream.Size n := FFileStreamSize
// 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 end else begin
CreateFileStream; CreateFileStream;
Result := FFileStream.Size; Result := FFileStreamSize;
end; end;
end; end;
@ -238,6 +249,7 @@ begin
CreateFileStream; CreateFileStream;
if IsWritingMode then begin if IsWritingMode then begin
Result := FFileStream.Read(Buffer, Count); Result := FFileStream.Read(Buffer, Count);
FFileStreamPos := FFileStream.Position;
end else begin end else begin
FillBuffer; FillBuffer;
Result := FMemoryStream.Read(Buffer, Count); Result := FMemoryStream.Read(Buffer, Count);
@ -256,6 +268,7 @@ begin
FlushBuffer; FlushBuffer;
FFileStream.Position := p; FFileStream.Position := p;
Result := FFileStream.Read(Buffer, Count); Result := FFileStream.Read(Buffer, Count);
FFileStreamPos := p + Count;
end else begin end else begin
FillBuffer; FillBuffer;
Result := FMemoryStream.Read(Buffer, Count); Result := FMemoryStream.Read(Buffer, Count);
@ -285,10 +298,12 @@ begin
CreateFileStream; CreateFileStream;
// case #2: New position is within buffer, file stream exists // case #2: New position is within buffer, file stream exists
if (newPos >= FFileStream.Position) and (newPos < FFileStream.Position + FMemoryStream.Size) // if (newPos >= FFileStream.Position) and (newPos < FFileStream.Position + FMemoryStream.Size)
if (newPos >= FFileStreamPos) and (newPos < FFileStreamPos + FMemoryStream.Size)
then begin then begin
FMemoryStream.Position := newPos - FFileStream.Position; // FMemoryStream.Position := newPos - FFileStream.Position;
Result := FMemoryStream.Position; FMemoryStream.Position := newPos - FFileStreamPos;
Result := newpos; //FMemoryStream.Position;
exit; exit;
end; end;
@ -296,6 +311,7 @@ begin
if IsWritingMode then if IsWritingMode then
FlushBuffer; FlushBuffer;
FFileStream.Position := newPos; FFileStream.Position := newPos;
FFileStreamPos := newPos;
FMemoryStream.Position := 0; FMemoryStream.Position := 0;
if not IsWritingMode then if not IsWritingMode then
FillBuffer; FillBuffer;
@ -306,17 +322,20 @@ var
savedPos: Int64; savedPos: Int64;
begin begin
// Case #1: Bytes fit into buffer // Case #1: Bytes fit into buffer
if FMemoryStream.Position + ACount < FBufSize then begin if FMemoryStream.Position + ACount < FBufSize then
begin
Result := FMemoryStream.Write(ABuffer, ACount); Result := FMemoryStream.Write(ABuffer, ACount);
FBufWritten := false; FBufWritten := false;
exit; end else
end;
// Case #2: Buffer would overflow // Case #2: Buffer would overflow
savedPos := GetPosition; begin;
FlushBuffer; savedPos := GetPosition;
FFileStream.Position := savedPos; FlushBuffer;
Result := FFileStream.Write(ABuffer, ACount); FFileStream.Position := savedPos;
Result := FFileStream.Write(ABuffer, ACount);
FFileStreamPos := savedPos + ACount;
FFileStreamSize := FFileStream.Size;
end;
end; end;

View File

@ -69,6 +69,7 @@
<Unit6> <Unit6>
<Filename Value="internaltests.pas"/> <Filename Value="internaltests.pas"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
<UnitName Value="internaltests"/>
</Unit6> </Unit6>
<Unit7> <Unit7>
<Filename Value="formattests.pas"/> <Filename Value="formattests.pas"/>