如何从字符串生成流?

问题描述 投票:0回答:14

我需要为采用来自文本文件的流的方法编写单元测试。我想做这样的事情:

Stream s = GenerateStreamFromString("a,b \n c,d");
c# unit-testing string stream
14个回答
1256
投票
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?


1031
投票

另一个解决方案:

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

122
投票

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

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
}

66
投票
public Stream GenerateStreamFromString(string s)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(s));
}

50
投票

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

30
投票

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

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

26
投票

使用

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

您随后需要在直播中使用

TextReader
吗?如果是这样,您可以直接提供
StringReader
,并绕过
MemoryStream
Encoding
步骤。


18
投票

我们使用下面列出的扩展方法。我认为你应该让开发人员对编码做出决定,这样就少了一些魔法。

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

14
投票

如果您需要更改编码,我投票支持@ShaunBowe的解决方案。但这里的每个答案都至少将整个字符串复制到内存中一次。带有

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

并且here是一个更完整的解决方案,具有必要的边界检查(源自

MemoryStream
,因此它也具有
ToArray
WriteTo
方法)。


12
投票

现在使用 C# 11,我们可以用一行完成此操作:

var ms = new MemoryStream("some string"u8.ToArray());

有关 Utf8 字符串文字的详细信息可以在此处找到 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-11.0/utf8-string-literals#detailed-design


9
投票

我认为您可以从使用MemoryStream中受益。您可以使用通过使用 Encoding 类GetBytes 方法获得的字符串字节来填充它。


9
投票

给你:

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

0
投票

使用可以通过扩展方法完成的内存流。

public static class StreamExtensions {
    public static Stream ToStream(this string @this, Encoding encoding) => new MemoryStream(encoding.GetBytes(@this));
    public static Stream ToStream(this string @this) => new MemoryStream(Encoding.UTF8.GetBytes(@this));
}

也可以使用使用函数式编程的一次性构建块。不返回内存流,而是返回字节数组并尽快关闭内存流。

使用这种方法我们可以有一个扩展方法:

public static class Disposable {    
    public static TResult Using<TDisposable, TResult>(Func<TDisposable> factory, Func<TDisposable, TResult> fn) where TDisposable : IDisposable {
        using (var disp = factory()){
            return fn(disp);            
        }
    }
}

这里还有一些演示用法:

string someLatin = "Si vis pacem para bellum";

var bytes = Disposable.Using(() => new MemoryStream(), mem => { mem.Write(Encoding.UTF8.GetBytes(someLatin)); return mem.ToArray(); });
Console.WriteLine(Encoding.UTF8.GetString(bytes.ToArray()));

您的测试将有一个字节数组,并且需要担心的副作用更少,例如流躺在周围并且必须稍后处理。如果除了从流中读出字节数组之外,您还打算在测试中进一步执行一些特定的流操作,那么这可能不是一个选择。


-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;
}
© www.soinside.com 2019 - 2024. All rights reserved.