tags:

views:

328

answers:

2

I'm working with a 3rd party component that returns an IStream object (System.Runtime.InteropServices.ComTypes.IStream). I need to take the data in that IStream and write it to a file. I've managed to get that done, but I'm not really happy with the code.

With "strm" being my IStream, here's my test code...

// access the structure containing statistical info about the stream
System.Runtime.InteropServices.ComTypes.STATSTG stat;
strm.Stat(out stat, 0);
System.IntPtr myPtr = (IntPtr)0;

// get the "cbSize" member from the stat structure
// this is the size (in bytes) of our stream.
int strmSize = (int)stat.cbSize; // *** DANGEROUS *** (long to int cast)
byte[] strmInfo = new byte[strmSize];
strm.Read(strmInfo, strmSize, myPtr);

string outFile = @"c:\test.db3";
File.WriteAllBytes(outFile, strmInfo);

At the very least, I don't like the long to int cast as commented above, but I wonder if there's not a better way to get the original stream length than the above? I'm somewhat new to C#, so thanks for any pointers.

+2  A: 

You don't need to do that cast, as you can read data from IStream source in chunks.

// ...
System.IntPtr myPtr = (IntPtr)-1;
using (FileStream fs = new FileStream(@"c:\test.db3", FileMode.OpenOrCreate))
{
    byte[] buffer = new byte[8192];
    while (myPtr.ToInt32() > 0)
    {
        strm.Read(buffer, buffer.Length, myPtr);
        fs.Write(buffer, 0, myPtr.ToInt32());
    }
}

This way (if works) is more memory efficient, as it just uses a small memory block to transfer data between that streams.

Rubens Farias
you was faster...
Arthur
Rubens - thanks for the above sample code. It definitely clarifies some things for me. Unfortunately, I haven't been in a position to test this since I posted it, and won't be for a bit longer. At that time, I'll either accept this answer, or post for more clarification if needed.
Jeff Godfrey
okidoki, ty for your feedback!
Rubens Farias
A: 

System.Runtime.InteropServices.ComTypes.IStream is a wrapper for ISequentialStream.

From MSDN: http://msdn.microsoft.com/en-us/library/aa380011%28VS.85%29.aspx

The actual number of bytes read can be less than the number of bytes requested if an error occurs or if the end of the stream is reached during the read operation. The number of bytes returned should always be compared to the number of bytes requested. If the number of bytes returned is less than the number of bytes requested, it usually means the Read method attempted to read past the end of the stream.

This documentation says, that you can loop and read as long as pcbRead is less then cb.

Arthur
Arthur - thanks for the link. More documentation is always welcomed...
Jeff Godfrey