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文書を試しても問題なく開きますが、明らかなものがありませんか?
あなたが求めることを忘れました:
str.CopyTo(data);
data.Seek(0, SeekOrigin.Begin); // <-- missing line
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
オプション:
data.Seek
を使用やや単純なPosition
プロパティを使用します。
data.Position = 0;
ToArray
のMemoryStream
呼び出しを使用して、開始するのがより簡単になります。
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は入力ストリームを閉じます。
メモリストリームの位置をリセットするのを忘れました:
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));
}
}
あなたが必要
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);
}