51

我正在尝试将对象写入 Xml 字符串并将该字符串保存到数据库中。但首先我需要得到字符串......

    private static readonly Encoding LocalEncoding = Encoding.UTF8;

    public static string SaveToString<T> (T settings)
    {
        Stream stream = null;
        TextWriter writer = null;
        string settingsString = null;

        try
        {
            stream = new MemoryStream();

            var serializer = new XmlSerializer(typeof(T));

            writer = new StreamWriter(stream, LocalEncoding);

            serializer.Serialize(writer, settings);

            var buffer = new byte[stream.Length];

            stream.Read(buffer, 0, (int)stream.Length);
            
            settingsString = LocalEncoding.GetString(buffer);
        }
        catch (Exception ex)
        {
            // If the action cancels we don't want to throw, just return null.
        }
        finally
        {
            if (stream != null)
                stream.Close();

            if (writer != null)
                writer.Close();
        }

        return settingsString;
    }

这似乎有效,流被字节填充。但是当我把它读回缓冲区然后读入字符串时......缓冲区充满了'0'!不知道我在这里做错了什么。

4

4 回答 4

85

如果您检查了 的结果stream.Read,您会发现它没有读取任何内容 - 因为您没有倒带流。(您可以使用 . 来执行此操作stream.Position = 0;。)但是,调用 更容易ToArray

settingsString = LocalEncoding.GetString(stream.ToArray());

(您需要将 from 的类型更改为streamto StreamMemoryStream但这没关系,因为它与您创建它的方法相同。)

或者 - 甚至更简单 - 只需使用StringWriter而不是StreamWriter. 如果您想使用 UTF-8 而不是 UTF-16,则需要创建一个子类,但这很容易。有关示例,请参见此答案。

顺便说一句,我担心你只是捕捉Exception假设它意味着无害的东西 - 甚至没有记录任何东西。请注意,using语句通常比编写显式finally块更干净。

于 2012-05-04T09:30:16.953 回答
36
string result = System.Text.Encoding.UTF8.GetString(fs.ToArray());
于 2015-01-29T15:20:01.633 回答
12
string result = Encoding.UTF8.GetString((stream as MemoryStream).ToArray());
于 2015-10-19T22:40:08.273 回答
5

在流长度非常大的情况下,由于大对象堆存在内存泄漏的危险。即stream.ToArray创建的字节缓冲区在堆内存中创建了内存流的副本,导致保留内存的重复。我建议使用 a StreamReader, a并在缓冲区TextWriter块中读取流。char

在netstandard2.0System.IO.StreamReader中有一个方法ReadBlock

您可以使用此方法来读取 Stream 的实例(也是 MemoryStream 实例,因为 Stream 是 MemoryStream 的父级):

private static string ReadStreamInChunks(Stream stream, int chunkLength)
{
    stream.Seek(0, SeekOrigin.Begin);
    string result;
    using(var textWriter = new StringWriter())
    using (var reader = new StreamReader(stream))
    {
        var readChunk = new char[chunkLength];
        int readChunkLength;
        //do while: is useful for the last iteration in case readChunkLength < chunkLength
        do
        {
            readChunkLength = reader.ReadBlock(readChunk, 0, chunkLength);
            textWriter.Write(readChunk,0,readChunkLength);
        } while (readChunkLength > 0);

        result = textWriter.ToString();
    }

    return result;
}

注意。由于使用了MemoryStream,内存泄漏的危害并没有完全消除,可能导致大内存流实例(memoryStreamInstance.Size >85000 bytes)的内存泄漏。您可以使用Recyclable Memory stream,以避免 LOH。这是相关的图书馆

于 2018-09-13T08:14:12.527 回答