Ответ 1
Вы забыли искать:
str.CopyTo(data);
data.Seek(0, SeekOrigin.Begin); // <-- missing line
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
Сейчас я пишу службу WCF, которая позволит веб-сайту ASP.Net извлекать файлы (на основе этой статьи). Моя проблема в том, что когда я возвращаю поток, он пуст.
Для простоты я выделил код в простое приложение winforms, чтобы попытаться найти, что проблема с возвратом потока, и это код:
private Stream TestStream()
{
Stream fs = File.OpenRead(@"c:\testdocument.docx");
return fs;
}
// This method converts the filestream into a byte array so that when it is
// used in my ASP.Net project the file can be sent using response.Write
private void Test()
{
System.IO.MemoryStream data = new System.IO.MemoryStream();
System.IO.Stream str = TestStream();
str.CopyTo(data);
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
}
Результатом этого кода является то, что buf
имеет длину 12 587 байт (правильная длина файла), но он просто содержит 0.
Документ Word открывается без проблем, если я его попробую, я пропущу что-то очевидное?
Вы забыли искать:
str.CopyTo(data);
data.Seek(0, SeekOrigin.Begin); // <-- missing line
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
Параметры:
data.Seek
как предложено ken2kИспользуйте несколько более простое свойство Position
:
data.Position = 0;
Используйте вызов ToArray
в MemoryStream
, чтобы упростить вашу жизнь:
byte[] buf = data.ToArray();
Третий вариант - мой предпочтительный подход.
Обратите внимание, что для закрытия потока файлов автоматически (и необязательно для MemoryStream
) должен быть оператор using
, и я бы добавил директиву использования для System.IO
, чтобы сделать ваш код более чистым:
byte[] buf;
using (MemoryStream data = new MemoryStream())
{
using (Stream file = TestStream())
{
file.CopyTo(data);
buf = data.ToArray();
}
}
// Use buf
Вы также можете создать метод расширения на Stream
, чтобы сделать это для вас в одном месте, например.
public static byte[] CopyToArray(this Stream input)
{
using (MemoryStream memoryStream = new MemoryStream())
{
input.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
Обратите внимание, что это не закрывает входной поток.
Вы забыли reset позицию потока памяти:
private void Test()
{
System.IO.MemoryStream data = new System.IO.MemoryStream();
System.IO.Stream str = TestStream();
str.CopyTo(data);
// Reset memory stream
data.Seek(0, SeekOrigin.Begin);
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
}
Update:
Следует отметить еще одну вещь: обычно приходится не игнорировать возвращаемые значения методов. Более надежная реализация должна проверять, сколько байтов было прочитано после возврата вызова:
private void Test()
{
using(MemoryStream data = new MemoryStream())
{
using(Stream str = TestStream())
{
str.CopyTo(data);
}
// Reset memory stream
data.Seek(0, SeekOrigin.Begin);
byte[] buf = new byte[data.Length];
int bytesRead = data.Read(buf, 0, buf.Length);
Debug.Assert(bytesRead == data.Length,
String.Format("Expected to read {0} bytes, but read {1}.",
data.Length, bytesRead));
}
}
Вам нужно
str.CopyTo(data);
data.Position = 0; // reset to beginning
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
И поскольку ваш метод Test()
имитирует клиента, он должен Close()
или Dispose()
поток str
. И memoryStream тоже, просто из принципала.
Попробуйте изменить свой код на это:
private void Test()
{
System.IO.MemoryStream data = new System.IO.MemoryStream(TestStream());
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
}