web-dev-qa-db-ja.com

File.OpenRead()からストリームを返す

ASP.Net Webサイトがファイルを取得できるようにするWCFサービスを作成中です( この記事 に基づいています)。私の問題は、ストリームを返すときに空になることです。

簡単にするために、コードを単純な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文書を試しても問題なく開きますが、明らかなものがありませんか?

48

あなたが求めることを忘れました:

str.CopyTo(data);
data.Seek(0, SeekOrigin.Begin); // <-- missing line
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
39
ken2k

オプション:

  • Ken2kが提案するdata.Seekを使用
  • やや単純なPositionプロパティを使用します。

    data.Position = 0;
    
  • ToArrayMemoryStream呼び出しを使用して、開始するのがより簡単になります。

    byte[] buf = data.ToArray();
    

3番目のオプションは、私の好みのアプローチです。

ファイルストリームを自動的に閉じる(およびオプションでusingの)MemoryStreamステートメントが必要であり、コードクリーナーを作成するためにSystem.IOのusingディレクティブを追加する必要があることに注意してください。

byte[] buf;
using (MemoryStream data = new MemoryStream())
{
    using (Stream file = TestStream())
    {
        file.CopyTo(data);
        buf = data.ToArray();
    }
}

// Use buf

Streamに拡張メソッドを作成して、これを1か所で行うこともできます。

public static byte[] CopyToArray(this Stream input)
{
    using (MemoryStream memoryStream = new MemoryStream())
    {
        input.CopyTo(memoryStream);
        return memoryStream.ToArray();
    }
}

このdoes n'tは入力ストリームを閉じます。

15
Jon Skeet

メモリストリームの位置をリセットするのを忘れました:

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

更新:

もう1つ注意すべき点があります。通常は、メソッドの戻り値を無視しないことを意味します。より堅牢な実装では、呼び出しが返された後に読み取られたバイト数を確認する必要があります。

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

あなたが必要

    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も、プリンシパルから外れています。

3
Henk Holterman

コードを次のように変更してみてください。

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

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