Возврат потока из File.OpenRead () - PullRequest
48 голосов
/ 05 января 2012

Я нахожусь в процессе написания службы 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.если я попробую, я упускаю что-то очевидное?

Ответы [ 5 ]

39 голосов
/ 05 января 2012

Вы забыли искать:

str.CopyTo(data);
data.Seek(0, SeekOrigin.Begin); // <-- missing line
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
15 голосов
/ 05 января 2012

Параметры:

  • Используйте data.Seek, как предложено ken2k
  • Используйте несколько более простое Position свойство:

    data.Position = 0;
    
  • Используйте вызов ToArray в MemoryStream, чтобы начать свою жизнь проще:

    byte[] buf = data.ToArray();
    

Третий вариант будет моим предпочтительным подходом.

Обратите внимание, что у вас должен быть оператор using для автоматического закрытия потока файлов (и, необязательно, для 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();
    }
}

Обратите внимание, что не закрывает входной поток.

5 голосов
/ 05 января 2012

Вы забыли сбросить позицию потока памяти:

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

Обновление:

Есть еще одна вещь, на которую стоит обратить внимание: обычно стоит не игнорировать возвращаемые значения методов. Более надежная реализация должна проверять, сколько байтов было прочитано после возврата вызова:

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));
    }                     
}
3 голосов
/ 05 января 2012

Вам нужно

    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 Stream. И memoryStream тоже просто из принципала.

1 голос
/ 05 января 2012

Попробуйте изменить свой код на это:

private void Test()
{            
    System.IO.MemoryStream data = new System.IO.MemoryStream(TestStream());

    byte[] buf = new byte[data.Length];
    data.Read(buf, 0, buf.Length);                       
}
...