1008

入力ストリームからバイト配列を作成するための推奨される方法は何ですか?

これが、.NET 3.5 を使用した現在のソリューションです。

Stream s;
byte[] b;

using (BinaryReader br = new BinaryReader(s))
{
    b = br.ReadBytes((int)s.Length);
}

ストリームのチャンクを読み書きする方が良い考えですか?

4

17 に答える 17

1389

信頼できるかどうかにかかっています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 4Stream.CopyTo以降では、基本的にコード内のループと同等の を使用しMemoryStreamます。ジョブ完了。stream.CopyTo(ms)ms.ToArray()

私の答えが他の答えよりも長い理由を説明する必要があるかもしれません。Stream.Read要求されたすべてを読み取ることを保証するものではありません。たとえば、ネットワーク ストリームから読み取りを行っている場合、すぐにデータが増える場合でも、1 パケット分の読み取りを行ってから戻る場合があります。BinaryReader.Readストリームの終わりまたは指定したサイズまで続行しますが、開始するサイズを知る必要があります。

上記のメソッドはMemoryStream、データがなくなるまで読み取り (および a へのコピー) を続けます。次にMemoryStream、配列内のデータのコピーを返すように要求します。開始するサイズがわかっている場合、または確実ではなくサイズを知っていると思わMemoryStreamれる場合は、をそのサイズで開始するように構成できます。同様に、最後にチェックを入れることができ、ストリームの長さがバッファーと同じサイズ ( によって返されるMemoryStream.GetBuffer) の場合は、バッファーを返すことができます。したがって、上記のコードは完全には最適化されていませんが、少なくとも正しいでしょう。ストリームを閉じる責任は負いません。呼び出し元がそれを行う必要があります。

詳細(および代替実装)については、この記事を参照してください。

于 2008-10-21T13:45:57.500 に答える
827

Jon の答えは正しいですが、彼は .NET に既に存在するコードを書き直していますCopyTo。したがって、.Net 4 の場合は Sandip のソリューションを使用しますが、以前のバージョンの .Net の場合は Jon の回答を使用します。Sandip のコードはCopyTo、多くの状況で例外が発生する可能性が非常に高く、破棄MemoryStreamされないままになるため、"using" を使用することで改善されます。

public static byte[] ReadFully(Stream input)
{
    using (MemoryStream ms = new MemoryStream())
    {
        input.CopyTo(ms);
        return ms.ToArray();
    }
}
于 2011-07-05T16:45:39.760 に答える
122

あなたがすでに持っている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);
    }
}
于 2010-04-13T14:54:01.430 に答える
73
MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();
于 2011-02-12T13:33:29.263 に答える
55

ほんの数セント...私がよく使用する方法は、このようなメソッドをカスタムヘルパーとして整理することです

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            input.CopyTo(ms);
            return ms.ToArray();
        }
    }
}

名前空間を構成ファイルに追加し、必要な場所で使用します

于 2013-02-18T16:01:22.587 に答える
20

たとえば、単に MemoryStream クラスの ToArray() メソッドを使用できます。

MemoryStream ms = (MemoryStream)dataInStream;
byte[] imageBytes = ms.ToArray();
于 2018-07-11T19:21:03.320 に答える
14

あなたはそれを拡張機能でより魅力的にすることさえできます:

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()
于 2012-07-18T17:01:12.830 に答える
8

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);
}
于 2011-05-31T00:55:31.820 に答える
4

上記のものは問題ありません...しかし、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;
        }'
于 2012-07-30T22:22:24.473 に答える
4

ヘルパー クラスを作成し、使用したい場所で参照します。

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            input.CopyTo(ms);
            return ms.ToArray();
        }
    }
}
于 2018-09-20T13:28:44.783 に答える
2

ストリームが Length プロパティをサポートしている場合、バイト配列を直接作成できます。利点はMemoryStream.ToArray、配列を 2 回作成することです。さらに、おそらくバッファ内の未使用の余分なバイトがいくつかあります。このソリューションは、必要な正確な配列を割り当てます。ストリームが Length プロパティをサポートしていない場合、NotSupportedException例外がスローされます。

また、配列は int.MaxValue よりも大きくできないことに注意してください。

public static async Task<byte[]> ToArrayAsync(this Stream stream)
{
    var array = new byte[stream.Length];
    await stream.ReadAsync(array, 0, (int)stream.Length);
    return array;
}

ストリームがシークをサポートしているかどうかに基づいて両方のバージョンを切り替える完全なコード。

/// <summary>
/// Converts stream to byte array.
/// </summary>
/// <param name="stream">Stream</param>
/// <returns>Binary data from stream in an array</returns>
public static async Task<byte[]> ToArrayAsync(this Stream stream)
{
    if (!stream.CanRead)
    {
        throw new AccessViolationException("Stream cannot be read");
    }

    if (stream.CanSeek)
    {
        return await ToArrayAsyncDirect(stream);
    }
    else
    {
        return await ToArrayAsyncGeneral(stream);
    }
}

private static async Task<byte[]> ToArrayAsyncGeneral(Stream stream)
{
    using (var memoryStream = new MemoryStream())
    {
        await stream.CopyToAsync(memoryStream);
        return memoryStream.ToArray();
    }
}

private static async Task<byte[]> ToArrayAsyncDirect(Stream stream)
{
    var array = new byte[stream.Length];
    await stream.ReadAsync(array, 0, (int)stream.Length);
    return array;
}
于 2021-09-23T11:41:35.550 に答える