C# でStream
a を aに変換する簡単な方法または方法はありますか?byte[]
12 に答える
私が知っている最短の解決策:
using(var memoryStream = new MemoryStream())
{
sourceStream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
次のような関数を呼び出す
byte[] m_Bytes = StreamHelper.ReadToEnd (mystream);
関数:
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = 0;
if(stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
}
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
if(stream.CanSeek)
{
stream.Position = originalPosition;
}
}
}
.NET Framework 4以降では、Stream
クラスにCopyTo
使用できる組み込みメソッドがあります。
フレームワークの以前のバージョンの場合、持っている便利なヘルパー関数は次のとおりです。
public static void CopyStream(Stream input, Stream output)
{
byte[] b = new byte[32768];
int r;
while ((r = input.Read(b, 0, b.Length)) > 0)
output.Write(b, 0, r);
}
次に、上記のメソッドの1つを使用して、にコピーしてMemoryStream
呼び出しますGetBuffer
。
var file = new FileStream("c:\\foo.txt", FileMode.Open);
var mem = new MemoryStream();
// If using .NET 4 or later:
file.CopyTo(mem);
// Otherwise:
CopyStream(file, mem);
// getting the internal buffer (no additional copying)
byte[] buffer = mem.GetBuffer();
long length = mem.Length; // the actual length of the data
// (the array may be longer)
// if you need the array to be exactly as long as the data
byte[] truncated = mem.ToArray(); // makes another copy
編集:元々、プロパティStream
をサポートするaに対してJasonの回答を使用することを提案しました。しかし、はすべてのコンテンツを1つで返すLength
と想定していたため、欠陥がありました。これは必ずしも正しいとは限りません(たとえば、ではありません) 。BCLに実装の例があるかどうかはわかりません。はサポートしますが、要求よりも短いチャンクでデータを返す可能性がありますが、誰でも継承できるため、これは簡単に当てはまります。Stream
Read
Socket
Stream
Length
Stream
ほとんどの場合、上記の一般的な解決策を使用する方がおそらく簡単ですが、次のような配列に直接読み込みたいと仮定しますbigEnough
。
byte[] b = new byte[bigEnough];
int r, offset;
while ((r = input.Read(b, offset, b.Length - offset)) > 0)
offset += r;
つまりRead
、データを保存する位置を繰り返し呼び出して移動します。
byte[] buf; // byte array
Stream stream=Page.Request.InputStream; //initialise new stream
buf = new byte[stream.Length]; //declare arraysize
stream.Read(buf, 0, buf.Length); // read from stream to byte array
わかりました、ここで何かが足りないかもしれませんが、これが私のやり方です:
public static Byte[] ToByteArray(this Stream stream) {
Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length);
Byte[] buffer = new Byte[length];
stream.Read(buffer, 0, length);
return buffer;
}
Stream s;
int len = (int)s.Length;
byte[] b = new byte[len];
int pos = 0;
while((r = s.Read(b, pos, len - pos)) > 0) {
pos += r;
}
もう少し複雑な解決策が必要s.Length
ですInt32.MaxValue
。しかし、それほど大きなストリームをメモリに読み込む必要がある場合は、問題に対する別のアプローチを検討することをお勧めします。
編集: ストリームがプロパティをサポートしていない場合は、Length
Earwicker の回避策を使用して変更します。
public static class StreamExtensions {
// Credit to Earwicker
public static void CopyStream(this Stream input, Stream output) {
byte[] b = new byte[32768];
int r;
while ((r = input.Read(b, 0, b.Length)) > 0) {
output.Write(b, 0, r);
}
}
}
[...]
Stream s;
MemoryStream ms = new MemoryStream();
s.CopyStream(ms);
byte[] b = ms.GetBuffer();
また、一度にパーツを読み込んで、返されるバイト配列を拡張してみることもできます。
public byte[] StreamToByteArray(string fileName)
{
byte[] total_stream = new byte[0];
using (Stream input = File.Open(fileName, FileMode.Open, FileAccess.Read))
{
byte[] stream_array = new byte[0];
// Setup whatever read size you want (small here for testing)
byte[] buffer = new byte[32];// * 1024];
int read = 0;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
stream_array = new byte[total_stream.Length + read];
total_stream.CopyTo(stream_array, 0);
Array.Copy(buffer, 0, stream_array, total_stream.Length, read);
total_stream = stream_array;
}
}
return total_stream;
}
迅速で汚いテクニック:
static byte[] StreamToByteArray(Stream inputStream)
{
if (!inputStream.CanRead)
{
throw new ArgumentException();
}
// This is optional
if (inputStream.CanSeek)
{
inputStream.Seek(0, SeekOrigin.Begin);
}
byte[] output = new byte[inputStream.Length];
int bytesRead = inputStream.Read(output, 0, output.Length);
Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length");
return output;
}
テスト:
static void Main(string[] args)
{
byte[] data;
string path = @"C:\Windows\System32\notepad.exe";
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
{
data = StreamToByteArray(fs);
}
Debug.Assert(data.Length > 0);
Debug.Assert(new FileInfo(path).Length == data.Length);
}
ストリームの内容をコピーしたい場合、なぜストリームをbyte []に読み込みたいのか、MemoryStreamを使用して入力ストリームをメモリストリームに書き込むことをお勧めします。
「bigEnough」配列は少しストレッチです。確かに、バッファーは「大容量」である必要がありますが、アプリケーションの適切な設計には、トランザクションと区切り文字を含める必要があります。この構成では、各トランザクションは事前設定された長さを持つため、配列は特定のバイト数を予測し、それを正しいサイズのバッファーに挿入します。デリミタはトランザクションの整合性を保証し、各トランザクション内で提供されます。アプリケーションをさらに改善するには、2 つのチャネル (2 つのソケット) を使用できます。データチャネルを使用して転送されるデータトランザクションのサイズおよびシーケンス番号に関する情報を含む固定長制御メッセージトランザクションを通信する。受信者はバッファの作成を確認し、それからデータが送信されます。ストリーム送信者を制御できない場合は、バッファとして多次元配列が必要です。コンポーネント配列は、予想されるデータの見積もりに基づいて、管理しやすいほど小さく、実用的に十分な大きさです。プロセス ロジックは、後続の要素配列で既知の開始区切り記号と終了区切り記号を検索します。終了デリミタが見つかると、デリミタ間の関連データを格納するために新しいバッファが作成され、データを破棄できるように初期バッファを再構築する必要があります。
ストリームをバイト配列に変換するコードは以下のとおりです。
Stream s = yourStream;
int streamEnd = Convert.ToInt32(s.Length);
byte[] buffer = new byte[streamEnd];
s.Read(buffer, 0, streamEnd);