Как сохранить IStream в файл через С#?

Я работаю со сторонним компонентом, который возвращает объект IStream (System.Runtime.InteropServices.ComTypes.IStream). Мне нужно взять данные из этого IStream и записать их в файл. Мне удалось это сделать, но я не очень доволен кодом.

Поскольку "strm" является моим IStream, вот мой тестовый код...

// 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);

По крайней мере, мне не нравится приведение long к int, как указано выше, но мне интересно, нет ли лучшего способа получить исходную длину потока, чем приведенный выше? Я немного новичок в C#, поэтому спасибо за любые указатели.


person Jeff Godfrey    schedule 15.10.2009    source источник


Ответы (2)


Вам не нужно делать это приведение, так как вы можете считывать данные из IStream источника по частям.

// ...
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());
    }
}

Этот способ (если работает) более эффективен с точки зрения использования памяти, поскольку он просто использует небольшой блок памяти для передачи данных между этими потоками.

person Rubens Farias    schedule 15.10.2009
comment
Рубенс - спасибо за приведенный выше пример кода. Это определенно проясняет некоторые вещи для меня. К сожалению, у меня не было возможности проверить это с тех пор, как я опубликовал его, и не буду в ближайшее время. В то время я либо приму этот ответ, либо опубликую для получения дополнительных разъяснений, если это необходимо. - person Jeff Godfrey; 20.10.2009
comment
myPtr должен быть инициализирован чем-то выше 0, так как он никогда не войдет в цикл while, если значение инициализации равно -1. - person Bill Tarbell; 19.05.2016
comment
Вам нужно фактически выделить немного памяти для этого указателя, а не просто добавить в него значение, иначе myPtr не будет содержать ничего полезного. И вы должны прочитать значение; myPtr.ToInt32() делает не то, что вы думаете. Кроме того, количество прочитанных байтов равно long, поэтому вам нужно прочитать значение Int64 и привести его. - person Herohtar; 20.11.2019

System.Runtime.InteropServices.ComTypes.IStream — это оболочка для ISequentialStream.

Из MSDN: http://msdn.microsoft.com/en-us/library/aa380011(VS.85).aspx

Фактическое количество прочитанных байтов может быть меньше запрошенного количества байтов, если возникает ошибка или если во время операции чтения достигается конец потока. Количество возвращаемых байтов всегда следует сравнивать с количеством запрошенных байтов. Если количество возвращенных байтов меньше, чем количество запрошенных байтов, это обычно означает, что метод Read попытался прочитать за концом потока.

В этой документации сказано, что вы можете зацикливаться и читать до тех пор, пока pcbRead меньше, чем cb.

person Arthur    schedule 15.10.2009