如何从字符串生成流?

Omu*_*Omu 710 c# string unit-testing stream

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

Stream s = GenerateStreamFromString("a,b \n c,d");
Run Code Online (Sandbox Code Playgroud)

Cam*_*and 906

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

别忘了使用:

using (var stream = GenerateStreamFromString("a,b \n c,d"))
{
    // ... Do stuff to stream
}
Run Code Online (Sandbox Code Playgroud)

关于StreamWriter不被处置.StreamWriter它只是基本流的包装器,不使用任何需要处理的资源.该Dispose方法将关闭底层StreamStreamWriter被写入.在这种情况下,MemoryStream我们想要返回.

在.NET 4.5中,现在有一个重载,StreamWriter它可以在编写器被处理后保持底层流的打开,但是这个代码也做同样的事情并且也适用于其他版本的.NET.

请参阅是否有任何方法可以在不关闭其BaseStream的情况下关闭StreamWriter?

  • 需要指出的一个重要观点是,流由字节组成,而字符串由字符组成.至关重要的是要理解将字符转换为一个或多个字节(或在这种情况下转换为流)__always__使用(或假设)特定编码.这个答案在某些情况下是正确的,使用默认编码,一般可能不合适.将Encoding明确地传递给StreamWriter构造函数会使作者更需要考虑编码的含义. (126认同)
  • @Ben是的.如果丢弃StreamWriter,底层流也将被关闭.我们不希望这样.Writer是一次性使用的唯一原因是清理流,因此可以安全地忽略它. (11认同)
  • 您说"不要忘记使用Using"来使用流,但在您的`GenerateStreamFromString`方法中,您没有使用Using with the StreamWriter.是否有一个原因? (5认同)
  • 还应该注意,整个字符串被复制到一个对大字符串很重要的内存中,因为现在我们在内存中有一个额外的副本. (2认同)

joe*_*net 680

另一种方案:

public static MemoryStream GenerateStreamFromString(string value)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
}
Run Code Online (Sandbox Code Playgroud)

  • 为了防止有人使用XML字符串反序列化,我必须将UTF8切换为Unicode才能在没有标志的情况下工作.好帖子!!! (30认同)
  • 这是非常紧凑的语法,但它会导致很多byte []的分配,所以要注意高性能代码. (4认同)
  • 我喜欢这一点(用Rhyous的微调和少量多余的糖作为扩展方法)比公认的答案更好;更灵活,更少的LOC和更少的涉及的对象(无需明确使用StreamWriter) (2认同)
  • `new MemoryStream(Encoding.UTF8.GetBytes("\ufeff" + (value ?? ""))` 如果您需要在流的开头包含 BOM (2认同)
  • 该解决方案仍然留下了使流只读的机会。`new MemoryStream( value, false )`。如果必须使用流写入器写入流,则无法将其设置为只读。 (2认同)

Jos*_*h G 106

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

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

这会添加一个扩展功能,您可以简单地:

using (var stringStream = "My string".ToStream())
{
    // use stringStream
}
Run Code Online (Sandbox Code Playgroud)

  • 当垃圾收集器清理`StreamWriter`时,我发现返回的流被关闭(导致半随机异常).解决方法是使用不同的构造函数 - 一个允许我指定**leaveOpen**的构造函数. (5认同)

War*_*ock 40

public Stream GenerateStreamFromString(string s)
{
    return new MemoryStream(Encoding.UTF8.GetBytes(s));
}
Run Code Online (Sandbox Code Playgroud)


Tim*_*son 23

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

你随后需要一个TextReader流吗?如果是这样,你可以提供一个StringReader直接,绕过MemoryStreamEncoding步骤.


Rob*_*ide 18

我使用了这样的答案:

public static Stream ToStream(this string str, Encoding enc = null)
{
    enc = enc ?? Encoding.UTF8;
    return new MemoryStream(enc.GetBytes(str ?? ""));
}
Run Code Online (Sandbox Code Playgroud)

然后我像这样使用它:

String someStr="This is a Test";
Encoding enc = getEncodingFromSomeWhere();
using (Stream stream = someStr.ToStream(enc))
{
    // Do something with the stream....
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*owe 11

我们使用下面列出的扩展方法.我认为你应该让开发人员对编码做出决定,因此所涉及的魔法就更少了.

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

  • 我更愿意将第一个方法实现为“return ToStream(s, Encoding.UTF8);”。在当前的实现中(“return s.ToStream(Encoding.UTF8);”),开发人员被迫更加努力地思考以掌握代码,并且似乎“s == null”的情况未得到处理并抛出“NullReferenceException”。 (2认同)

cjk*_*cjk 9

干得好:

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


Nic*_* N. 9

扩展方法的现代化版本和稍作修改的版本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));
Run Code Online (Sandbox Code Playgroud)

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

  • `public static Stream ToStream(这个字符串值,Encoding 编码 = null) => new MemoryStream((encoding ?? Encoding.UTF8).GetBytes(value ?? string.Empty));` (2认同)

Kon*_*man 8

我想你可以从使用MemoryStream中受益.您可以使用Encoding类GetBytes方法填充您获得的字符串字节.


Gyö*_*zeg 8

如果您需要更改编码,我会为@ShaunBowe的解决方案投票。但是这里的每个答案至少将整个字符串复制到内存中一次。ToCharArray+BlockCopy组合的答案做两次。

如果这很重要,这里是Stream原始 UTF-16 字符串的简单包装器。如果与StreamReaderselect 一起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; // ;)     
}
Run Code Online (Sandbox Code Playgroud)

这里是必要的约束检查一个更完整的解决方案(源自MemoryStream因此它具有ToArrayWriteTo方法以及)。


Rom*_*iak 5

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

var ms = new MemoryStream("some string"u8.ToArray());
Run Code Online (Sandbox Code Playgroud)

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