入力ストリームからバイト配列を作成するための好ましい方法は何ですか?
これが.NET 3.5での私の現在の解決策です。
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
ストリームの塊を読み書きするのは、まだ良い考えでしょうか。
それは本当にあなたがs.Length
を信頼できるかどうかにかかっています。多くのストリームでは、どれだけのデータがあるのかわかりません。そのような場合 - そして.NET 4より前の - 私はこのようなコードを使用したいと思います:
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
.NET 4以降では、私は Stream.CopyTo
を使用します。これは、コード内のループと基本的に同じです - MemoryStream
を作成し、stream.CopyTo(ms)
を呼び出してからms.ToArray()
を返します。仕事は終わった。
私の回答が他の回答よりも長い理由を説明する必要があります。 Stream.Read
は、要求されたすべてを読み取ることを保証しません。たとえば、ネットワークストリームから読み取っている場合は、すぐにデータが増えても、1パケット分を読み取って戻ってくる可能性があります。 BinaryReader.Read
はストリームの終わりまたは指定したサイズまで続きますが、それでも最初のサイズを知る必要があります。
上記のメソッドは、データがなくなるまで読み取り(およびMemoryStream
へのコピー)を続けます。それから、配列のデータのコピーを返すようにMemoryStream
に要求します。あなたが始めるサイズを知っているなら - またはthinkあなたは確かにサイズを知っています - あなたはその最初のサイズになるようにMemoryStream
を作ることができます。同様に、末尾にチェックを入れることができ、ストリームの長さがバッファと同じサイズ( MemoryStream.GetBuffer
によって返される)である場合は、単にバッファを返すことができます。そのため、上記のコードは最適化されていませんが、少なくとも正しいものになります。それはストリームを閉じることについて一切の責任を負いません - 呼び出し側がそれをするべきです。
より多くの情報(および代替の実装)については この記事 を参照してください。
Jonの答えは正しいのですが、彼は既にCopyTo
に存在するコードを書き換えています。したがって、.NET 4ではSandipのソリューションを使用しますが、以前のバージョンの.NETではJonの回答を使用します。 CopyTo
の例外は、多くの場合非常にありそうなものであり、MemoryStream
を破棄しないままにするので、Sandipのコードは "using"の使用によって改善されます。
public static byte[] ReadFully(Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
あなたがMemoryStreamを持っているのなら、あなたはすでにそのためのmemorystream.ToArray()
を持っているということを指摘したいだけです。
また、未知または異なるサブタイプのストリームを処理していて、MemoryStream
を受け取ることができる場合は、そのような場合には上記の方法を使用し、それでも他の人には受け入れられた答えを使用できます。
public static byte[] StreamToByteArray(Stream stream)
{
if (stream is MemoryStream)
{
return ((MemoryStream)stream).ToArray();
}
else
{
// Jon Skeet's accepted answer
return ReadFully(stream);
}
}
MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();
ちょうど私のカップルセント...私がよく使う慣習は、カスタムヘルパーとしてこのようなメソッドをまとめることです。
public static class StreamHelpers
{
public static byte[] ReadFully(this Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
}
設定ファイルに名前空間を追加し、好きな場所でそれを使う
あなたはそれを拡張でより空想にすることさえできます:
namespace Foo
{
public static class Extensions
{
public static byte[] ToByteArray(this Stream stream)
{
using (stream)
{
using (MemoryStream memStream = new MemoryStream())
{
stream.CopyTo(memStream);
return memStream.ToArray();
}
}
}
}
}
そしてそれを通常のメソッドとして呼び出します。
byte[] arr = someStream.ToByteArray()
たとえば、MemoryStreamクラスのToArray()メソッドを使用するだけです。
MemoryStream ms = (MemoryStream)dataInStream;
byte[] imageBytes = ms.ToArray();
Bob(つまり質問者)のコードでコンパイル時エラーが発生します。 Stream.Lengthはlongですが、BinaryReader.ReadBytesは整数パラメータを取ります。私の場合は、長精度を必要とするほどの大きさのStreamsを扱うことを期待していませんので、次のようにします。
Stream s;
byte[] b;
if (s.Length > int.MaxValue) {
throw new Exception("This stream is larger than the conversion algorithm can currently handle.");
}
using (var br = new BinaryReader(s)) {
b = br.ReadBytes((int)s.Length);
}
上記の1つは問題ありませんが、SMTP経由で送信するとデータが破損する可能性があります(必要な場合)。私はバイトごとに正しくバイトを送るのを助ける他の何かに変更しました: '
using System;
using System.IO;
private static byte[] ReadFully(string input)
{
FileStream sourceFile = new FileStream(input, FileMode.Open); //Open streamer
BinaryReader binReader = new BinaryReader(sourceFile);
byte[] output = new byte[sourceFile.Length]; //create byte array of size file
for (long i = 0; i < sourceFile.Length; i++)
output[i] = binReader.ReadByte(); //read until done
sourceFile.Close(); //dispose streamer
binReader.Close(); //dispose reader
return output;
}'
ヘルパークラスを作成し、それを使用したい場所ならどこでもそれを参照します。
public static class StreamHelpers
{
public static byte[] ReadFully(this Stream input)
{
using (MemoryStream ms = new MemoryStream())
{
input.CopyTo(ms);
return ms.ToArray();
}
}
}
だれでもそれを好む場合、これはMemoryStreamの不必要なDispose呼び出しなしで拡張メソッドとして形成された.NET 4+のみのソリューションです。これは絶望的な些細な最適化ですが、MemoryStreamを破棄しないことが実際の失敗ではないことは注目に値します。
public static class StreamHelpers
{
public static byte[] ReadFully(this Stream input)
{
var ms = new MemoryStream();
input.CopyTo(ms);
return ms.ToArray();
}
}
名前空間RestSharp.Extensionsには、メソッドReadAsBytesがあります。このメソッドの内部にはMemoryStreamが使用されており、このページのいくつかの例と同じコードがありますが、RestSharpを使用している場合はこれが最も簡単な方法です。
using RestSharp.Extensions;
var byteArray = inputStream.ReadAsBytes();
この拡張方法を使うことができます。
public static class StreamExtensions
{
public static byte[] ToByteArray(this Stream stream)
{
var bytes = new List<byte>();
int b;
while ((b = stream.ReadByte()) != -1)
bytes.Add((byte)b);
return bytes.ToArray();
}
}
これは私が使っていてテストしてうまく機能した関数です。 'input'をnullにしないでください。 'input.position'は読み込む前に '0'にリセットする必要があります。そうしないと読み込みループが中断され、配列に変換するための読み込みが行われません。
public static byte[] StreamToByteArray(Stream input)
{
if (input == null)
return null;
byte[] buffer = new byte[16 * 1024];
input.Position = 0;
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
byte[] temp = ms.ToArray();
return temp;
}
}