MemoryStream.ToArray() return 如果 StreamWriter 没有被释放,则为空数组

MemoryStream.ToArray() return empty array if StreamWriter is not disposed

我正在尝试从我的模型中获取字节数组以将其放入文件中。我有这样的方法:

        public static byte[] GetByteArray(List<MyModel> models)
    {
        using var ms = new MemoryStream();
        using var sw = new StreamWriter(ms);

        foreach (var model in models)
        {
            sw.Write(model.Id + "," + model.Name);
            sw.WriteLine();
        }

        sw.Dispose();
        return ms.ToArray();
    }

此方法工作正常,但我可能认为我不需要手动处理 StreamWriter,因为我有一个 using 语句。我也这么想,但是当我删除 sw.Dispose();ms.ToArray(); returns 一个空数组。有人可以向我解释这种行为吗?

dispose 完成了部分工作。它冲洗了作家。使用 Flush() 手动刷新它。

public static byte[] GetByteArray(List<MyModel> models)
{
    var ms = new MemoryStream();
    using var sw = new StreamWriter(ms);

    foreach (var model in models)
    {
        sw.Write(model.Id + "," + model.Name);
        sw.WriteLine();
    }

    // flush the writer, to make sure it is written to the stream.
    sw.Flush();
    return ms.ToArray();
}

您不需要处置内存流,因为 StreamWriter 拥有所有权。

我不喜欢 streamwriter 拥有内存流的结构。这可能是因为 streamwriter 也可以直接在文件上使用。具有文件路径作为参数的构造函数。 (所以不需要流参数)

StreamWriter leaveOpen constructor

你有这条线:

using var sw = new StreamWriter(ms);

这只会在方法末尾处理 StreamWriter。但是,您在方法结束前ms.ToArray() 调用。这意味着您在 StreamWriter 被释放之前调用 ms.ToArray()

但是,StreamWriter 正在内部缓冲一些数据,并且仅在处理时将其刷新到 MemoryStream。因此,您需要确保在 调用 ms.ToArray().

之前处理 StreamWriter

使用旧的 using 语法可能更清楚,它明确说明何时发生处置:

public static byte[] GetByteArray(List<MyModel> models)
{
    using var ms = new MemoryStream();
    using (var sw = new StreamWriter(ms))
    {
        foreach (var model in models)
        {
            sw.Write(model.Id + "," + model.Name);
            sw.WriteLine();
        }
    }

    return ms.ToArray();
}

如果将 List<MyModel> 项写成字符串,可以通过以下方式简化转换:

public static byte[] GetByteArray(List<MyModel> models) =>
    Encoding.UTF8.GetBytes(string.Join(Environment.NewLine, 
                                       models.Select(model => $"{model.Id},{model.Name}")));

或使用第三方序列化程序,例如 Newtonsoft.Json(示例来自 here):

public static byte[] Serialize<T>(this T source)
{
    var asString = JsonConvert.SerializeObject(source, SerializerSettings);
    return Encoding.Unicode.GetBytes(asString);
}

public static T Deserialize<T>(this byte[] source)
{
    var asString = Encoding.Unicode.GetString(source);
    return JsonConvert.DeserializeObject<T>(asString);
}

正如其他人提到的,您必须刷新 StreamWriter
这是您的函数的样子:

public static byte[] GetByteArray(List<MyModel> models)
{
    MemoryStream memoryStream = new MemoryStream();
    try
    {
        StreamWriter streamWriter = new StreamWriter(memoryStream);
        try
        {
            List<MyModel>.Enumerator enumerator = models.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    MyModel current = enumerator.Current;
                    streamWriter.Write(string.Concat(current.Id, ",", current.Name));
                    streamWriter.WriteLine();
                }
            }
            finally
            {
                ((IDisposable)enumerator).Dispose();
            }
            streamWriter.Dispose();
            return memoryStream.ToArray();
        }
        finally
        {
            if (streamWriter != null)
            {
                ((IDisposable)streamWriter).Dispose();
            }
        }
    }
    finally
    {
        if (memoryStream != null)
        {
            ((IDisposable)memoryStream).Dispose();
        }
    }
}