如何从字符串生成流?

我需要为一个方法编写一个单元测试,该方法接受来自文本文件的流。我想做这样的事情:

Stream s = GenerateStreamFromString("a,b \n c,d");
741358 次浏览

使用MemoryStream类,调用Encoding.GetBytes首先将字符串转换为字节数组。

您随后是否需要流上的TextReader?如果是这样,您可以直接提供StringReader,并绕过MemoryStreamEncoding步骤。

我认为您可以从使用内存流中受益。您可以使用编码类GetBytes方法获得的字符串字节填充它。

在这里你去:

private Stream GenerateStreamFromString(String p){Byte[] bytes = UTF8Encoding.GetBytes(p);MemoryStream strm = new MemoryStream();strm.Write(bytes, 0, bytes.Length);return strm;}
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只是基流的包装器,不使用任何需要处理的资源。Dispose方法将关闭StreamWriter正在写入的底层Stream。在这种情况下,这就是我们要返回的MemoryStream

在. NET 4.5中,现在有一个StreamWriter的重载,它在写入器被处理后保持底层流打开,但此代码做同样的事情并与其他版本的. NET一起工作。

有没有办法关闭StreamWriter而不关闭其BaseStream?

另一种解决方案:

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

将其添加到静态字符串实用程序类中:

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}

String扩展的良好组合:

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;}
public Stream GenerateStreamFromString(string s){return new MemoryStream(Encoding.UTF8.GetBytes(s));}

我使用了这样的混合答案:

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....}

我们使用下面列出的扩展方法。我认为你应该让开发人员对编码做出决定,这样就不那么神奇了。

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 ?? ""));}}

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));

@Palec对@Shaun Bowe答案的评论中建议的修改。


或者作为一行(由@satnhak建议):

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

如果你需要更改编码,我投票支持@陈志立的解决方案。但是这里的每个答案都至少在内存中复制整个字符串一次。ToCharArray+BlockCopy组合的答案做了两次。

如果这很重要,这里是原始UTF-16字符串的简单Stream包装器。如果与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 checkvar 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方法)。