Copy a memory stream into a byte array

Ok here is a very simple one, but I need an answer quick please.

I have a memory stream (tmemorystream) and I need to put the contents of the memory stream into a byte array.

Here is what i tried to do but I've obviously done something wrong as it doesnt work

function TMainForm.convertTobytearray;

var
  TEncoded : String;
  SomeStream : tmemorystream;
  bufs : array of byte;

begin

//SNIP unimportant code//

  SomeStream := TMemoryStream.Create;
  SomeStream := HTTPSend(Tencoded);
  setlength(bufs,somestream.size);
  somestream.Read(bufs,somestream.size);
  showmessage(pchar(somestream.memory));
end;

If I step through the code, I see that a byte array of 6 bytes is allocated (the same as the size of the tmemorystream) but the bytes are all 00's but the memorystream contains actual binary data

I'm sure I have just missed something simple

Thanks in advance for any help

Luke
lukeMHAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

pritaeasSoftware EngineerCommented:
A TMemoryStream has a Buffer property which is what need. But you'll have to look at the source to see how to access it. I don't have access to Delphi for the time being.

hth, pritaeas
0
Russell LibbySoftware Engineer, Advisory Commented:

Simple example. Notice the use of the first element of the byte array, otherwise the dynamic array will get clobbered.

Regards,
Russell

type
  TByteArray  =  Array of Byte;

function StreamToByteArray(Stream: TStream): TByteArray;
begin

  // Check stream
  if Assigned(Stream) then
  begin
     // Reset stream position
     Stream.Position:=0;
     // Allocate size
     SetLength(result, Stream.Size);
     // Read contents of stream
     Stream.Read(result[0], Stream.Size);
  end
  else
     // Clear result
     SetLength(result, 0);

end;

procedure TForm1.Button1Click(Sender: TObject);
var  bytes:      TByteArray;
     strmMem:    TMemoryStream;
     lpBytes:    Array [0..100] of Byte;
     dwIndex:    Integer;
begin

  for dwIndex:=0 to 100 do lpBytes[dwIndex]:=dwIndex;

  strmMem:=TMemoryStream.Create;
  strmMem.Write(lpBytes, SizeOf(lpBytes));

  bytes:=StreamToByteArray(strmMem);

  if CompareMem(bytes, @lpBytes, 100) then
     ShowMessage('Success')
  else
     ShowMessage('Failure');

  strmMem.Free;

end;

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
lukeMHAuthor Commented:
Where do i put

type
  TByteArray  =  Array of Byte;

?

Thanks

Luke
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

Russell LibbySoftware Engineer, Advisory Commented:

Define it pretty much anywhere..... just so long as it appears before usage. But please note, I only defined it so I could demo a function that returned that data type. You could just put the code inline, as in your example, and not have to define it at all, eg:

var
  TEncoded : String;
  SomeStream : tmemorystream;
  bufs : array of byte;

begin

//SNIP unimportant code//

  SomeStream := TMemoryStream.Create;
  SomeStream := HTTPSend(Tencoded);
  setlength(bufs,somestream.size);
  somestream.Read(bufs[0],somestream.size); // <- change
  showmessage(pchar(somestream.memory));
end;

The ** ONLY ** purpose of the demo was to illustrate the real problem. By passing the zero element, you are really passing the address of the first element of the array, vs the array itself. For dynamic arrays this does make a difference.


Russell


0
lukeMHAuthor Commented:
Hi,

I changed the line in my code like you suggested, but this didn't seem to do anything as buf is still an array or 0's

Kind Regards

Luke
0
Russell LibbySoftware Engineer, Advisory Commented:

Luke,

Did you check to make sure that the stream was reset (position:=0) before attempting the Read? A Stream.Read will read from the current position, which if at the end of the stream will read nothing.

var
  TEncoded : String;
  SomeStream : tmemorystream;
  bufs : array of byte;
  dwRead:     Integer;
begin

  SomeStream:=TMemoryStream.Create;
  SomeStream:=HTTPSend(Tencoded);
  MessageBox(0, PChar(Format('Stream size = %d, Steam Position = %d', [SomeStream.Size, SomeStream.Position])), nil, MB_OK);

  SetLength(bufs, SomeStream.size);
  SomeStream.Position:=0;
  dwRead:=SomeStream.Read(bufs[0], SomeStream.size);
  MessageBox(0, PChar(Format('Number of bytes read = %d', [dwRead])), nil, MB_OK);

  MessageBox(0, SomeStream.Memory, nil, MB_OK);

end;


Regards,
Russell

0
lukeMHAuthor Commented:
doh!

I think you may well be right there, just going to check it out and if all is well points shall be awarded to you

Thanks and regards

Luke
0
BlackTigerXCommented:
you can use
TByteDynArray

which is defined in the unit: Types

also beaware that TByteArray is already defined in the SysUtils unit, you wouldn't want to use that name as to not cause conflicts
0
lukeMHAuthor Commented:
rllibby you've got it,

Thanks everyone else for your comments

Kind Regards

Luke
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.