<Samuel Aeschbacher> wrote in message news:✉forums.embarcadero.com...
> I use TFileStream to read the data, then copying the filestream to a
> stringstream
> for better string handling. If I seek a substring in
> Stringstream.DataString, I get an
> "Out-of-memory-Exception" if the size of the Stream exceeds 200 MB (it
> worked
> well with a size <= 136 MB and crashed with a size >= 280 MB).
In pre-D2009 versions, TStringStream derived directly from TStream, used an
AnsiString as its data storage (hense its name), and the DataString property
provided direct access to that data.
In D2009 and later, TStringStream now derives from TByteStream, thus uses a
TBytes for its data storage, and the DataString property no longer provides
direct access to the data. It returns a temporary UnicodeString that is
converted from the raw TBytes data using the new Encoding property.
The code you are using is not taking into account TStringStream's
re-designed functionality for Unicode in D2009 and later. If you want to
maintain the original Ansi-based logic, then something like this:
{code:delphi}
function TDLHI_Main.ImportKompendium(var MsgList: TListBox; var PrgrssBar:
TProgressBar; FileName : string): string;
var
pmem, p: PAnsiChar;
i : integer;
begin
Result := '';
mstrm := TMemoryStream.Create;
try
mstrm.LoadFromFile(FileName);
pmem := PAnsiChar(mstrm.Memory);
p := StrPos(pmem, '<OK_ERROR>');
if p <> nil then
i := Integer(p - pmem) + 1
else
i := 0;
...
finally
mstrm.Free;
end;
end;
{code}
Alternatively, implement an AnsiString-based TStream class so you can
preserve your original code, eg:
{code}
type
TAnsiStringStream = class(TStream)
private
FDataString: AnsiString;
FPosition: Integer;
protected
procedure SetSize(NewSize: Longint); override;
public
constructor Create(const AString: AnsiString);
function Read(var Buffer; Count: Longint): Longint; override;
function ReadString(Count: Longint): AnsiString;
function Seek(Offset: Longint; Origin: Word): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
procedure WriteString(const AString: AnsiString);
property DataString: AnsiString read FDataString;
end;
constructor TAnsiStringStream.Create(const AString: AnsiString);
begin
inherited Create;
FDataString := AString;
end;
function TAnsiStringStream.Read(var Buffer; Count: Longint): Longint;
begin
Result := Length(FDataString) - FPosition;
if Result > Count then Result := Count;
Move(PAnsiChar(@FDataString[FPosition + SizeOf(AnsiChar)])^, Buffer,
Result * SizeOf(AnsiChar));
Inc(FPosition, Result);
end;
function TAnsiStringStream.Write(const Buffer; Count: Longint): Longint;
begin
Result := Count;
SetLength(FDataString, (FPosition + Result));
Move(Buffer, PAnsiChar(@FDataString[FPosition + SizeOf(AnsiChar)])^,
Result * SizeOf(AnsiChar));
Inc(FPosition, Result);
end;
function TAnsiStringStream.Seek(Offset: Longint; Origin: Word): Longint;
begin
case Origin of
soFromBeginning: FPosition := Offset;
soFromCurrent: FPosition := FPosition + Offset;
soFromEnd: FPosition := Length(FDataString) - Offset;
end;
if FPosition > Length(FDataString) then
FPosition := Length(FDataString)
else if FPosition < 0 then FPosition := 0;
Result := FPosition;
end;
function TAnsiStringStream.ReadString(Count: Longint): string;
var
Len: Integer;
begin
Len := Length(FDataString) - FPosition;
if Len > Count then Len := Count;
SetString(Result, PChar(@FDataString[FPosition + SizeOf(Char)]), Len);
Inc(FPosition, Len);
end;
procedure TAnsiStringStream.WriteString(const AString: AnsiString);
begin
Write(PAnsiChar(AString)^, Length(AString) * SizeOf(AnsiChar));
end;
procedure TAnsiStringStream.SetSize(NewSize: Longint);
begin
SetLength(FDataString, NewSize);
if FPosition > NewSize then FPosition := NewSize;
end;
function TDLHI_Main.ImportKompendium(var MsgList: TListBox; var PrgrssBar:
TProgressBar; FileName : string): string;
var
i : integer;
begin
Result := '';
fs := TFileStream.Create(FileName, fmOpenRead + fmShareDenyWrite);
try
strstrm := TAnsiStringStream.Create('');
strstrm.CopyFrom(fs, fs.Size);
finally
fs.Free;
end;
i := AnsiStrings.AnsiPos('<OK_ERROR>', strstrm.DataString);
...
end;
{code}
> It's interesting, to get the exception on the "pos"-Statement and not as I
> expected on the copying of the stream.
If the stream contains 200MB of raw bytes, then the DataString property will
try to allocate a UnicodeString that uses (slightly more than) 400B of new
memory, on top of the 200MB that the stream is already holding on to. It is
unlikely that the memory manager will be able to find an available
contigious block of memory that large.
--
Remy Lebeau (TeamB)