Solved

Stream to pascal string conversion

Posted on 2000-02-27
16
610 Views
Last Modified: 2010-04-04
I need a conversion from TStream to "string", BUT:
- it has to support #0 's in the stream, and thus in the string
- at the end, the string length must be correct.
- it should be lightning fast and efficient.

The best I could make up:

for myInt := 0 to Stream.Size do
begin
   Stream.Read(myChar,1)
   Result := Result + myChar;
end;

But as you can see it uses a loop which fills a (dynamic growing) string. I'd like something more like allocate a string or memorypart, do a single conversion (some typecast or whatever) and put it in result. But I don't know how...

Any Ideas?
0
Comment
Question by:leon321
  • 5
  • 4
  • 4
  • +2
16 Comments
 
LVL 10

Expert Comment

by:ptmcomp
ID: 2562703
What's about this:

var
  s: String;
begin
  SetLength(s, Stream.Size);
  Sream.Position:=0;
  Stream.Read(PChar(s[1]), Stream.Size);
end;
(Not tested, but should work...)
ptm.
0
 

Author Comment

by:leon321
ID: 2562704
Off course I meant,
for myInt := 0 to (Stream.Size-1) do

Leon.
0
 
LVL 7

Expert Comment

by:ahalya
ID: 2562747
I use this to read a TMemoField into a string:

function TSearchForm.GetBlobAsString(Blob:TBlobField): string;

var
   BlobStream: TBlobStream;
   a: array [0..1024] of Char;
   i:longint;

begin
Result:='';
BlobStream := TBlobStream.Create(Blob, bmRead);
   try
   i := BlobStream.Size;
   FillChar(a, i, #0);
   FillChar(a, SizeOf(a), #0);
   BlobStream.Read(a, i);
   finally
   BlobStream.Free;
  end;
a[i] := #0; {set the last character as null}
Result:=StrPas(a);
end;
0
 
LVL 10

Expert Comment

by:ptmcomp
ID: 2562776
What's about this:

var
  s: String;
begin
  SetLength(s, Stream.Size);
  Sream.Position:=0;
  Stream.Read(PChar(s[1]), Stream.Size);
end;
(Not tested, but should work...)
ptm.
0
 

Author Comment

by:leon321
ID: 2562954
ptmcomp: you are using a explicit pchar typecast.
ahalya: you are using an implicit pchar typecast. (StrPas expects an pchar parameter)

Both cases, my value would be truncated at the first #0 occurence. This is exactly what I do not want.

If my stream would contain: 'something'#0'otherdata'
My pascal string would have to contain also the exact same data. (and not be truncated to 'something')

Regards,
Leon.










0
 
LVL 7

Expert Comment

by:ahalya
ID: 2563051
How about this ?  (btw, if i use long string and SetLength(s, i) then it raises an exception, but if you can live with a short string then this shd be ok)


  var
   BlobStream: TBlobStream;
   a: array [0..255] of Char;
    i:longint;
    s : shortstring;

 begin
 BlobStream := TBlobStream.Create(Blob, bmRead);
  i := BlobStream.Size;
  i := BlobStream.Read(a, i);
  BlobStream.Free;

  copyMemory(@s[1], @c, i);
  s[0] := chr(i);
  end;

0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 2563913
hi all,

what about this?

procedure TForm1.Button1Click(Sender: TObject);
var
  F : TMemoryStream;
  s : String;
begin
  F := TMemoryStream.Create;
  Try
    F.LoadFromFile('u:\zerostr.txt');
    SetString(s,PChar(F.Memory),F.Size);

    //Prepare for OutPut (windowControls don't like #0 chars in a string
    while pos(#0,s) <> 0 do s[pos(#0,s)] := #1;
    ShowMessage(s);
  finally
    F.Free;
  end;
end;

meikl
0
 

Expert Comment

by:aacrg
ID: 2564657
To Leon321
Sorry, but you're wrong about the typecasting Stream.Read(PChar(s[1]), Stream.Size) means the same as Stream.Read(@s[1], Stream.Size). The PChar is just refering the beginning of the memory where the data has to be stored.

0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:leon321
ID: 2570368
ptmcomp: you're first example I cannot compile: constant object cannot be passed as var parameter


ahalya : you're first example requires a buffer (you declared as 1024) bytes, but I need something dynamic. Since the stream could be 200k as well.

kretzschmar : I'm affraid the Memory property you're using, is only available in TMemoryStream, TStream does not have such property..

Regards,
Leon
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 2570511
to leon

you've never said which kind of stream you use
and nevertheless you can use
TMemoryStream.LoadFromStream(YourStream);
to get it into a TMemorystream

meikl
0
 
LVL 10

Accepted Solution

by:
ptmcomp earned 50 total points
ID: 2570794
Sorry, this one I could compile:

var
  s: String;
  Stream: TStream;
begin
  SetLength(s, Stream.Size);
  Stream.Position:=0;
  Stream.Read(s[1], Stream.Size);
end;

Regards, ptm. >;0)
0
 

Author Comment

by:leon321
ID: 2571760
I'm sorry Meikl, but the first line of my question contains "TStream to "string" ". So I meant all TStream descendants, not only TMemoryStream :(

ptmcomp, I'll try you're new example today!

Leon.
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 2571805
well leon,

what about this ?

function StreamToString(Stream : TStream) : String;
var ms : TMemoryStream;
begin
  Result := '';
  ms := TMemoryStream.Create;
  try
    ms.LoadFromStream(Stream);
    SetString(Result,ms.memory,ms.Size);
  finally
    ms.free;
  end;
end;

meikl
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 2571818
one correction

function StreamToString(Stream : TStream) : String;
var ms : TMemoryStream;
begin
  Result := '';
  ms := TMemoryStream.Create;
  try
    ms.LoadFromStream(Stream);
    SetString(Result,PChar(ms.memory),ms.Size);
  finally
    ms.free;
  end;
end;

//sample to call

procedure TForm1.Button2Click(Sender: TObject);
var
  fs : TFileStream;
  s : String;
begin
  Fs := TFileStream.Create('u:\zerostr.txt',fmOpenRead);
  Try
    s := StreamToString(fs);

    //Prepare for OutPut (windowControls don't like #0 chars in a string
    while pos(#0,s) <> 0 do s[pos(#0,s)] := #1;
    ShowMessage(s);
  finally
    Fs.Free;
  end;
end;

meikl
0
 

Author Comment

by:leon321
ID: 2573878
ptmcomp it works! Since you're the first, you'll get the points. The index on s[1] is the essential trick here, I tried something similar a few days ago without that index and it only gave access violations. (may be the compiler is not smart enough and references s[0] in that case..)

Either way, thanks all!

0
 
LVL 10

Expert Comment

by:ptmcomp
ID: 2574370
Fine. I think it would also work with Stream.Read(Pchar(s)^, Stream.Size) - all what you need is a dereferenced pointer to the beginning of the memory where to put the data.
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now