2012-01-05 10 views
39

私はASP.Net Webサイトが(this articleに基づいて)ファイルを取得できるようにするWCFサービスを作成中です。私の問題は、ストリームを返すときは空白だということです。File.OpenRead()からストリームを返す

は簡単にするために、私は試してみて、問題がストリームを返すにあるものを見つけるために、単純なリサイズアプリにコードを分離してきたし、これはコードです:

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文書が問題なく開きますが、何か明白なものがありませんか?

+1

管理者として実行していますか? 「マイドキュメント」またはルート以外の別のフォルダからドキュメントを引き出してみてください。 – keyboardP

+1

@keyboard - 良いアドバイスだけど、例外は発生し、 '0'と正しい長さは生成されません。 –

+0

@HenkHolterman - ああ、それは本当です。 – keyboardP

答えて

31

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

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

Kenさん、ありがとうございました。 – GrandMasterFlush

+0

シークが許可されていない場合はどうなりますか? –

1

はこれにあなたのコードを変更してみてください:

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

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

あなたTest()方法は、それがあるべきクライアントを模倣しているので、あなたが

str.CopyTo(data); 
    data.Position = 0; // reset to beginning 
    byte[] buf = new byte[data.Length]; 
    data.Read(buf, 0, buf.Length); 

を必要とし、 〜Close()またはDispose()str SおしゃべりそしてmemoryStreamも、まさにプリンシパルの外です。

+0

ありがとうHenk、うまくいきました。 WCFコードはそれに応じてストリームを閉じたり破棄したりしますが、これをテストアプリケーションに残しました。 – GrandMasterFlush

+0

私は集まったが、それはそれが不完全なテストアプリになります。 –

+0

合意しましたが、このアプリはテストハーネスまたは正式なテストに関係するものではなく、問題のテスト/デバッグ専用です。シンプルなアプリケーションにコードを移植し、サーバー上でWCFサービスを試してデバッグする方が簡単でした。 – GrandMasterFlush

12

オプション:

  • 使用data.Seek ken2k
  • により示唆されるように、やや単純Positionプロパティを使用します開始するにはあなたの人生をより簡単にするためにMemoryStreamToArray呼び出しを使用し

    data.Position = 0; 
    
  • をwith:

    byte[] buf = data.ToArray(); 
    

第3の選択肢が私の好みのアプローチです。

あなたは(MemoryStreamのために、必要に応じてと)自動的にファイルストリームを閉じますusing文を持つべき注意、と私はあなたのコードのクリーナーを作るために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(); 
    } 
} 

は注意してください。

+0

ありがとうジョン、それはそれを行うのははるかに良い方法です。 WCFサービスはusingステートメントを利用していますが、ここに投稿したときに読みやすくするためにテストコードから除外しました。 – GrandMasterFlush

5

あなたはメモリストリームの位置をリセットするのを忘れ:

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)); 
    }      
} 
関連する問題