如何从字符串生成流?


Answers:


956
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方法将关闭底层StreamStreamWriter被写入。在这种情况下,MemoryStream我们要返回。

在.NET 4.5中,现在有一个重载StreamWriter,可以在处置编写器后使基础流保持打开状态,但是此代码执行相同的操作,并且也适用于其他版本的.NET。

请参见是否可以在不关闭StreamWriter的BaseStream的情况下将其关闭?


134
需要指出的重要概念是,流由字节组成,而字符串由字符组成。至关重要的是要理解,将字符转换为一个或多个字节(或在这种情况下转换为流)始终使用(或假定)一种特定的编码。这个答案虽然在某些情况下是正确的,但是使用默认编码,通常可能不适合。明确地将Encoding传递给StreamWriter构造函数将使作者更加明显地需​​要考虑Encoding的含义。
drwatsoncode 2014年

6
您说“不要忘了使用Using”来使用流,但是在您的GenerateStreamFromString方法中,您并没有在StreamWriter中使用Using。是否有一个原因?

12
@本是的。如果处置StreamWriter,则基础流也将关闭。我们不想要那个。Writer可以抛弃的唯一原因是清理流,因此可以忽略。
卡梅伦·麦克法兰2015年

2
还应注意,整个字符串都被复制到内存中,这对于大字符串可能很重要,因为现在我们在内存中有一个额外的副本。
2013年

1
@ahong不是。StreamWriter反正可能在做您内部所说的话。优点是封装和更简单的代码,但以抽象化为代价,例如编码掉了。这取决于您要实现的目标。
卡梅隆·麦克法兰

723

另一个解决方案:

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

31
以防万一有人将其与XML字符串反序列化一起使用,我必须将UTF8切换为Unicode才能使其不带标志地工作。很棒的帖子!!!
Gaspa79 2014年

2
我喜欢这一点(将Rhyous的微调和少量的小糖用作扩展方法)比公认的答案更好;更灵活,更少的LOC和更少的对象(不需要StreamWriter)
KeithS 2015年

2
new MemoryStream(Encoding.UTF8.GetBytes("\ufeff" + (value ?? ""))如果需要在流的开头包含BOM表
robert4

5
这是一种非常紧凑的语法,但是它将导致很多byte []分配,因此请注意高性能代码。
michael.aird

1
此解决方案仍然留下了使流变为只读的机会。new MemoryStream( value, false )。如果必须使用流编写器编写流,则不能将其设为只读。
codekandis

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

这增加了扩展功能,因此您可以简单地:

using (var stringStream = "My string".ToStream())
{
    // use stringStream
}

5
我发现,垃圾回收器清理时,返回的流被关闭(导致半随机异常)StreamWriter。解决方法是使用另一种构造函数-一种允许我指定LeaveOpen的构造函数
Bevan 2015年

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

24

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

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


22

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

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

托马斯,为什么要投反对票?enc = enc ?? Encoding.UTF8允许我专门询问具有特定编码的流或UTF8的默认值,因为在.net(到目前为止,我使用.net 4.0)中,除了字符串以外,您不能在函数中提供默认类型的引用类型签名这行是必要的,这有意义吗?
Robocide '16

提到您需要将其放在单独的类(非通用静态类?)中也有帮助,并减少了反对票。
阿里

13

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

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

1
我宁愿将第一种方法实现为return ToStream(s, Encoding.UTF8);。在当前的实现中,(return s.ToStream(Encoding.UTF8);开发人员被迫更努力地思考代码,并且似乎s == null未处理并抛出该情况NullReferenceException。)
Palec

10

干得好:

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

1
写入后需要重置位置。最好使用构造函数,如joelnet的答案。
Jim Balter 2015年

10

扩展方法的现代化版本和稍作修改的版本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答案的评论中建议的修改。



3

如果您需要更改编码,我赞成@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; // ;)     
}

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


-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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.