我需要为一个从文本文件中获取流的方法编写单元测试。我想要做类似于这样的事情:
Stream s = GenerateStreamFromString("a,b \n c,d");
我需要为一个从文本文件中获取流的方法编写单元测试。我想要做类似于这样的事情:
Stream s = GenerateStreamFromString("a,b \n c,d");
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:
using (var stream = GenerateStreamFromString("a,b \n c,d"))
{
// ... Do stuff to stream
}
关于未被释放的StreamWriter
。 StreamWriter
只是基础流的封装器,并不使用需要被释放的资源。 Dispose
方法将关闭StreamWriter
正在写入的底层Stream
。在这种情况下,我们希望关闭的是MemoryStream
。StreamWriter
可以在编写器被释放后保持基础流处于打开状态,但这段代码也能实现同样的效果,在其他版本的.NET上也适用。Using
”,但是在您的GenerateStreamFromString
方法中,您没有在StreamWriter
中使用Using
。这是有原因的吗? - BenStreamWriter
大概已经在内部执行你所说的操作了。这样做的好处是封装和简化代码,但代价是把一些东西(比如编码)抽象掉了。这取决于你想要实现什么目标。 - Cameron MacFarland另一种解决方案:
public static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
}
new MemoryStream(value,false)
。如果您必须使用流作者来写入,则无法使流变为只读。 - codekandis将此代码添加到静态字符串实用类中:
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
}
StreamWriter
时,我发现返回的流会被关闭(导致半随机异常)。解决方法是使用一个允许我指定 leaveOpen 的不同构造函数。 - BevanStreamWriter
不应该被释放吗? - Métoulepublic Stream GenerateStreamFromString(string s)
{
return new MemoryStream(Encoding.UTF8.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));
public static Stream ToStream(this string value, Encoding encoding = null) => new MemoryStream((encoding ?? Encoding.UTF8).GetBytes(value ?? string.Empty));
- satnhak我使用了类似以下的答案混合:
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 Stream ToStream(this string str, Encoding enc = Encoding.UTF8)
{
return new MemoryStream(enc.GetBytes(str ?? ""));
}
- Matthew Lock使用MemoryStream
类,先调用Encoding.GetBytes
将您的字符串转换为字节数组。
之后,如果您需要在流上使用TextReader
,您可以直接提供一个StringReader
,跳过MemoryStream
和Encoding
步骤。
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 ?? ""));
}
}
return ToStream(s,Encoding.UTF8)
进行实现。 在当前的实现中(return s.ToStream(Encoding.UTF8)
),开发人员被迫更加努力地思考以理解代码,并且似乎未处理s == null
的情况,可能会抛出NullReferenceException
异常。 - Palec如果你需要更改编码,我建议使用@ShaunBowe的解决方案。但是这里的每个答案都至少将整个字符串复制到内存中一次。使用ToCharArray
+ BlockCopy
组合的答案则会复制两次。
如果这很重要,这里有一个简单的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
,因此还具有ToArray
和WriteTo
方法)。
这是你所需要的:
private Stream GenerateStreamFromString(String p)
{
Byte[] bytes = UTF8Encoding.GetBytes(p);
MemoryStream strm = new MemoryStream();
strm.Write(bytes, 0, bytes.Length);
return strm;
}