文字列からストリームを生成するにはどうすればよいですか?


759

テキストファイルからストリームを取得するメソッドの単体テストを記述する必要があります。私はこのようなことをしたいと思います:

Stream s = GenerateStreamFromString("a,b \n c,d");

メモリ節約ソリューションについてはStringReaderStreamstackoverflow.com
a / 55170901/254109を

回答:


956
public static Stream GenerateStreamFromString(string s)
{
    var stream = new MemoryStream();
    var writer = new StreamWriter(stream);
    writer.Write(s);
    writer.Flush();
    stream.Position = 0;
    return stream;
}

使用することを忘れないでください:

using (var stream = GenerateStreamFromString("a,b \n c,d"))
{
    // ... Do stuff to stream
}

StreamWriter処分されていないことについて。StreamWriter基本ストリームの単なるラッパーであり、破棄する必要のあるリソースを使用しません。このDisposeメソッドは、書き込み中の基になるStreamものを閉じStreamWriterます。この場合、それはMemoryStream私たちが返したいものです。

.NET 4.5ではStreamWriter、ライターが破棄された後も、基になるストリームを開いたままにするオーバーロードが存在しますが、このコードは同じことを行い、他のバージョンの.NETでも機能します。

参照してくださいそのBaseStreamを閉じずのStreamWriterを閉鎖する方法はありますか?


134
注意すべき重要なポイントの概念は、文字列は文字で構成されているのに対し、ストリームはバイトで構成されるということです。文字を1バイト以上(またはこの場合はStream)に変換する場合、常に特定のエンコーディングが使用(または想定)されることを理解することが重要です。この回答は正しい場合もありますが、デフォルトのエンコーディングを使用しており、一般的には適切ではない場合があります。EncodingをStreamWriterコンストラクターに明示的に渡すと、作成者がEncodingの影響を考慮する必要があることがより明確になります。
drwatsoncode 2014年

6
ストリームを使用するために「Usingを使用することを忘れないでください」と言いGenerateStreamFromStringますが、メソッドではStreamWriterでUsingを使用していません。これには理由がありますか?
Ben

12
@ベンはい。StreamWriterを破棄すると、基になるストリームも閉じられます。それは望まない。Writerが使い捨てである唯一の理由は、ストリームをクリーンアップすることなので、無視しても安全です。
Cameron MacFarland 2015年

2
また、文字列全体がメモリにコピーされることにも注意してください。これは、メモリに余分なコピーが1つあるため、大きな文字列では重要になる場合があります。
UGEEN、2016

1
@ahong本当にそうではありません。StreamWriterおそらくとにかくあなたが内部的に言ったことをやっています。利点はカプセル化とより単純なコードですが、エンコードなどの抽象化を犠牲にしています。それはあなたが達成しようとしていることに依存します。
Cameron MacFarland

724

別の解決策:

public static MemoryStream GenerateStreamFromString(string value)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
}

31
誰かがこれをXML文字列の逆シリアル化で使用する場合に備えて、フラグなしで機能するには、UTF8をUnicodeに切り替える必要がありました。素晴らしいポスト!!!
Gaspa79 2014

2
私はこれを受け入れた回答よりも気に入っています(Rhyosの微調整と拡張メソッドとして使用するためのささいな余分な砂糖を使用)。より柔軟で、LOCが少なく、関係するオブジェクトが少ない(StreamWriterを明示的に必要としない)
KeithS、2015年

2
new MemoryStream(Encoding.UTF8.GetBytes("\ufeff" + (value ?? ""))ストリームの最初にBOMを含める必要がある場合
robert4

5
これは非常にコンパクトな構文ですが、byte []の割り当てが多くなるため、高パフォーマンスのコードに注意してください。
michael.aird 2017年

1
このソリューションでも、ストリームを読み取り専用にする機会が残っていました。new MemoryStream( value, false )。ストリームライターで書き込む必要がある場合は、ストリームを読み取り専用にすることはできません。
codekandis 2018年

106

これを静的文字列ユーティリティクラスに追加します。

public static Stream ToStream(this string str)
{
    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write(str);
    writer.Flush();
    stream.Position = 0;
    return stream;
}

これにより、拡張関数が追加され、簡単に次のことができます。

using (var stringStream = "My string".ToStream())
{
    // use stringStream
}

5
ガベージコレクターがをクリーンアップすると、返されたストリームが閉じられる(セミランダムな例外が発生する)ことを発見しましたStreamWriter。修正は、異なるコンストラクターを使用することでした-これにより、leaveOpenを指定できました
Bevan 2015年


24

MemoryStreamクラスを使用して、Encoding.GetBytes最初に文字列をバイトの配列に変換します。

その後TextReader、ストリームが必要ですか?もしそうなら、あなたはStringReader直接供給し、MemoryStreamそしてEncodingステップをバイパスすることができます。


23

私はこのような答えを組み合わせて使用​​しました:

public static Stream ToStream(this string str, Encoding enc = null)
{
    enc = enc ?? Encoding.UTF8;
    return new MemoryStream(enc.GetBytes(str ?? ""));
}

そして、私はそれを次のように使用します:

String someStr="This is a Test";
Encoding enc = getEncodingFromSomeWhere();
using (Stream stream = someStr.ToStream(enc))
{
    // Do something with the stream....
}

トーマス、どうして投票しないの?enc = enc ?? Encoding.UTF8を使用すると、特定のエンコーディングまたはデフォルトのUTF8を使用してストリームを具体的に要求できます。.net(私が使用している限り、.net 4.0)では、文字列以外の参照型に関数のデフォルト値を指定できないためこの行の署名が必要ですが、それは意味がありますか?
ロボサイド2016

これを別のクラス(汎用の静的クラスではない?)に配置する必要があることを説明することも役立ち、反対票を減らすことができます。
2016年

13

以下の拡張メソッドを使用します。開発者がエンコーディングについて決定を下す必要があると私は思うので、関与する魔法は少なくなります。

public static class StringExtensions {

    public static Stream ToStream(this string s) {
        return s.ToStream(Encoding.UTF8);
    }

    public static Stream ToStream(this string s, Encoding encoding) {
        return new MemoryStream(encoding.GetBytes(s ?? ""));
    }
}

1
最初のメソッドをとして実装したいと思いreturn ToStream(s, Encoding.UTF8);ます。現在の実装では(return s.ToStream(Encoding.UTF8);、開発者がコードを把握するのは難しいと思うことを余儀なくされ、の場合は、と思われるs == null未処理であると投げるNullReferenceException
Palec

10

どうぞ:

private Stream GenerateStreamFromString(String p)
{
    Byte[] bytes = UTF8Encoding.GetBytes(p);
    MemoryStream strm = new MemoryStream();
    strm.Write(bytes, 0, bytes.Length);
    return strm;
}

1
書き込み後に位置をリセットする必要があります。joelnetの回答のように、コンストラクターを使用する方が良いでしょう。
ジムバルター、2015

10

の拡張メソッドの最新化され、わずかに変更されたバージョンToStream

public static Stream ToStream(this string value) => ToStream(value, Encoding.UTF8);

public static Stream ToStream(this string value, Encoding encoding) 
                          => new MemoryStream(encoding.GetBytes(value ?? string.Empty));

@Shaun Boweの回答に対する@Palecのコメントで提案されている変更。



4

エンコーディングを変更する必要がある場合は、@ ShaunBoweのソリューションに投票します。しかし、ここでのすべての回答は、文字列全体をメモリに少なくとも1回コピーします。ToCharArray+ BlockCopyコンボでの回答は、2回実行されます。

それが重要な場合、ここにStream生のUTF-16文字列の単純なラッパーがあります。StreamReader選択Encoding.Unicodeで使用する場合:

public class StringStream : Stream
{
    private readonly string str;

    public override bool CanRead => true;
    public override bool CanSeek => true;
    public override bool CanWrite => false;
    public override long Length => str.Length * 2;
    public override long Position { get; set; } // TODO: bounds check

    public StringStream(string s) => str = s ?? throw new ArgumentNullException(nameof(s));

    public override long Seek(long offset, SeekOrigin origin)
    {
        switch (origin)
        {
            case SeekOrigin.Begin:
                Position = offset;
                break;
            case SeekOrigin.Current:
                Position += offset;
                break;
            case SeekOrigin.End:
                Position = Length - offset;
                break;
        }

        return Position;
    }

    private byte this[int i] => (i & 1) == 0 ? (byte)(str[i / 2] & 0xFF) : (byte)(str[i / 2] >> 8);

    public override int Read(byte[] buffer, int offset, int count)
    {
        // TODO: bounds check
        var len = Math.Min(count, Length - Position);
        for (int i = 0; i < len; i++)
            buffer[offset++] = this[(int)(Position++)];
        return (int)len;
    }

    public override int ReadByte() => Position >= Length ? -1 : this[(int)Position++];
    public override void Flush() { }
    public override void SetLength(long value) => throw new NotSupportedException();
    public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
    public override string ToString() => str; // ;)     
}

そしてここに、必要なバインドされたチェックを備えたより完全なソリューションがあります(MemoryStreamそのようにしてメソッドToArrayWriteToメソッドから派生しています)。


-2

文字列拡張の適切な組み合わせ:

public static byte[] GetBytes(this string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

public static Stream ToStream(this string str)
{
    Stream StringStream = new MemoryStream();
    StringStream.Read(str.GetBytes(), 0, str.Length);
    return StringStream;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.