web-dev-qa-db-ja.com

ストリームへの文字列の書き込みと読み戻しが機能しない

文字列をストリーム(この場合はMemoryStream)に書き込み、バイトを1つずつ読み取りたいです。

stringAsStream = new MemoryStream();
UnicodeEncoding uniEncoding = new UnicodeEncoding();
String message = "Message";

stringAsStream.Write(uniEncoding.GetBytes(message), 0, message.Length);

Console.WriteLine("This:\t\t" + (char)uniEncoding.GetBytes(message)[0]);
Console.WriteLine("Differs from:\t" + (char)stringAsStream.ReadByte());

私が得る(望ましくない)結果は次のとおりです。

This:         M
Differs from: ?

looks「Message」の最初の文字は「M」であるため、正しく読み取られていないようです。これは、UnicodeEncodingインスタンスからバイトを取得するときに機能しますが、ストリームから読み戻すときは機能しません。

私は何を間違えていますか?


全体像:ストリームのバイトで動作するアルゴリズムがあります。できるだけ一般的になり、どのストリームでも動作するようにしたいと思います。 ASCII-StringをMemoryStreamに変換するか、別の方法を使用してStringをStreamとして処理できるようにします。問題のアルゴリズムは、ストリームのバイトに対して機能します。

37
Deleted

MemoryStreamに書き込んだ後、それを読み返す前に、SeekMemoryStreamの先頭に戻す必要があるので、最後からは読みません。

[〜#〜] update [〜#〜]

更新を確認した後、ストリームを構築するより信頼性の高い方法があると思います。

UnicodeEncoding uniEncoding = new UnicodeEncoding();
String message = "Message";

// You might not want to use the outer using statement that I have
// I wasn't sure how long you would need the MemoryStream object    
using(MemoryStream ms = new MemoryStream())
{
    var sw = new StreamWriter(ms, uniEncoding);
    try
    {
        sw.Write(message);
        sw.Flush();//otherwise you are risking empty stream
        ms.Seek(0, SeekOrigin.Begin);

        // Test and work with the stream here. 
        // If you need to start back at the beginning, be sure to Seek again.
    }
    finally
    {
        sw.Dispose();
    }
}

ご覧のとおり、このコードはStreamWriterを使用して、文字列全体を(適切なエンコーディングで)MemoryStreamに書き込みます。これにより、文字列のバイト配列全体が確実に書き込まれるようになります。

更新:空のストリームで何度か問題に取り組みました。書き終えた直後にFlushを呼び出すだけで十分です。

62
Justin Niessner

Delta's BlogString To MemoryStream(C#) からこの「ワンライナー」を試してください。

MemoryStream stringInMemoryStream =
   new MemoryStream(ASCIIEncoding.Default.GetBytes("Your string here"));

文字列は MemoryStream にロードされ、そこから読み取ることができます。 Encoding.GetBytes(...) を参照してください。これも 他のいくつかのエンコーディングで実装されています です。

34
Joel Purra

文字列内のcharactersの数を返すmessage.Lengthを使用していますが、bytes読み取ります。次のようなものを使用する必要があります。

byte[] messageBytes = uniEncoding.GetBytes(message);
stringAsStream.Write(messageBytes, 0, messageBytes.Length);

次に、単一のbyteを読み取り、charにキャストするだけでそこから文字を取得することを期待しています。 UnicodeEncodingは、文字ごとに2バイトを使用します。

ジャスティンが言うように、あなたはalsoストリームの先頭に戻ってシークしていません。

基本的に、ここではほとんどすべてが間違っていると思います。全体像を教えてください。私たちはあなたが何をすべきか本当にを解決するのを手伝います。書き込みにStreamWriterを使用し、次に読み取りにStreamReaderを使用することは、おそらくあなたが望んでいることですが、実際に示した短いコードだけではわかりません。

14
Jon Skeet

TextWriter、この場合は StreamWriter を使用してMemoryStreamに書き込む方がはるかに生産的だと思います。その後、他の人が言ったように、_stringAsStream.Position = 0L;_のようなものを使用してMemoryStreamを「巻き戻す」必要があります。

_stringAsStream = new MemoryStream();

// create stream writer with UTF-16 (Unicode) encoding to write to the memory stream
using(StreamWriter sWriter = new StreamWriter(stringAsStream, UnicodeEncoding.Unicode))
{
  sWriter.Write("Lorem ipsum.");
}
stringAsStream.Position = 0L; // rewind
_

ご了承ください:

StreamWriterは、特に指定がない限り、デフォルトでUTF8Encodingのインスタンスを使用します。 UTF8Encodingのこのインスタンスは、バイトオーダーマーク(BOM)なしで構築されます

また、通常new UnicodeEncoding()を作成する必要はありません。これは、便利なutf-8、utf-16、およびutf-32フレーバーで使用するクラスの静的メンバーとして既に存在しているためです。

そして、最後に(他の人が言ったように)bytesを直接charsに変換しようとしていますが、そうではありません。メモリストリームがあり、それが文字列であることがわかっていた場合、TextReaderを使用してバイトから文字列を取得します。生のバイトをいじるのは私にとって「危険」だ。

5
Benny Jobigan

ストリームを先頭にリセットする必要があります。

stringAsStream.Seek(0, SeekOrigin.Begin);
Console.WriteLine("Differs from:\t" + (char)stringAsStream.ReadByte());

これは、Positionプロパティを0に設定することでも実行できます。

stringAsStream.Position = 0
1
Oded