将String写入Stream并将其读回不起作用

Del*_*ted 37 c# stream

我想将一个String写入一个Stream(本例中是一个MemoryStream)并逐个读取这些字节.

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());
Run Code Online (Sandbox Code Playgroud)

我得到的(不受欢迎的)结果是:

This:         M
Differs from: ?
Run Code Online (Sandbox Code Playgroud)

看起来像它没有被正确读取,为"信息"的第一个字符是"M",从UnicodeEncoding实例获取字节时,但不读他们从流回来时,其工作原理.

我究竟做错了什么?


更大的图片:我有一个算法可以处理Stream的字节,我希望尽可能通用并使用任何Stream.我想将ASCII-String转换为MemoryStream,或者使用另一种方法将String作为Stream处理.有问题的算法将处理Stream的字节.

Jus*_*ner 63

写完之后MemoryStream,在你回读之前,你需要Seek回到开头,MemoryStream所以你不是从最后读.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,此代码使用StreamWriter将整个字符串(具有适当的编码)写入MemoryStream.这样可以避免确保写入字符串的整个字节数组.

更新:我几次遇到空流问题.在写完之后立即调用Flush就足够了.

  • 该代码将在`ms.Seek(0,SeekOrigin.Begin)`失败,因为在StreamWriter上放置一个use将关闭它的流,在本例中是MemoryStream.然后,当您尝试搜索时,它将为您提供"无法访问已关闭的流"异常. (9认同)
  • 如上所述,此代码无法编译.Joel Purra的答案是单线,效果更好. (3认同)

Joe*_*rra 36

试试Delta的Blog,String To MemoryStream(C#)中的 "one-liner" .

MemoryStream stringInMemoryStream =
   new MemoryStream(ASCIIEncoding.Default.GetBytes("Your string here"));
Run Code Online (Sandbox Code Playgroud)

该字符串将被加载到MemoryStream,您可以从中读取.请参阅Encoding.GetBytes(...),它也已针对其他一些编码实现.

  • 我强烈敦促使用此示例的任何人使用Encoding.UTF8 over ASCII - 或任何其他更广泛的编码.机会很好,非{美国,英国,...}人写的任何文字都会以ASCII格式呈现. (7认同)
  • 并取回数据,[`Encoding.ASCII.GetString(ms.ToArray());`](http://stackoverflow.com/a/234262/)。 (3认同)

Jon*_*eet 16

您使用message.Length它返回的数个字符的字符串中,但你应该使用的2-14 字节读取.你应该使用类似的东西:

byte[] messageBytes = uniEncoding.GetBytes(message);
stringAsStream.Write(messageBytes, 0, messageBytes.Length);
Run Code Online (Sandbox Code Playgroud)

然后你正在读取一个字节并希望通过转换来获取它的一个字符char.UnicodeEncoding每个字符将使用两个字节.

正如Justin所说,你没有回到流的开头.

基本上我担心这里的一切都是错的.请给我们更大的图片,我们可以帮你的工作,你应该什么真正的做.使用a StreamWriter来编写然后StreamReader用来读取很可能是你想要的,但是我们无法从你所展示的简短代码中得知.


Ben*_*gan 5

我认为使用TextWriter一个StreamWriter写入MemoryStream 会更高效.在那之后,正如其他人所说,你需要使用类似的东西来"回放"MemoryStream stringAsStream.Position = 0L;.

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
Run Code Online (Sandbox Code Playgroud)

注意:

除非另有说明,否则StreamWriter默认使用UTF8Encoding实例.这个UTF8Encoding实例的构造没有字节顺序标记(BOM)

此外,您不必创建new UnicodeEncoding()通常,因为已经有一个作为类的静态成员,您可以使用方便的utf-8,utf-16和utf-32风格.

然后,最后(正如其他人所说的那样)你试图将bytes直接转换为chars,而不是.如果我有一个内存流并且知道它是一个字符串,我会使用a TextReader从字节中获取字符串.对于原始字节来说,看起来"危险".