将内存流写入文件

15

我曾尝试将数据以json格式作为字符串检索并写入文件,效果非常好。现在我正在尝试使用MemoryStream做同样的事情,但文件中没有任何实际数据,只是 [{},{},{},{},{}]。

我的问题是 - 我该如何检查数据是否正确地传输到内存流中,或者问题发生在其他地方。我知道myList确实包含数据。

这是我的代码:

MemoryStream ms = new MemoryStream();
DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(List<myClass>));
dcjs.WriteObject(ms, myList);

using (FileStream fs = new FileStream(Path.Combine(Application.StartupPath,"MyFile.json"), FileMode.OpenOrCreate))
{
                ms.Position = 0;
                ms.Read(ms.ToArray(), 0, (int)ms.Length);
                fs.Write(ms.ToArray(), 0, ms.ToArray().Length);
                ms.Close();
                fs.Flush();
                fs.Close();
 }

不是说这会解决你的问题,但考虑使用Stream.CopyTo方法来清理代码。 - sstan
ms.Read(ms.ToArray(), 0, (int)ms.Length); 这句代码为什么要读取内存流并覆盖 dcjs.WriteObject 写入的内容呢?这似乎是你的问题所在,不要重置流位置并覆盖自身。 - Ron Beyer
你为什么在 FileStream 之前向 MemoryStream 写入呢?但是使用 .net 4.0,你应该可以访问 Stream.CopyTo(Stream)。 - Aron
我尝试了 ms.CopyTo(fs) 但得到了相同的结果。 - Coding Duchess
@ElenaDBA 问题不在于你的文件写入,而是在于你的序列化器。 - Aron
5个回答

62

有一个非常方便的方法,Stream.CopyTo(Stream)

using (MemoryStream ms = new MemoryStream())
{
    StreamWriter writer = new StreamWriter(ms);

    writer.WriteLine("asdasdasasdfasdasd");
    writer.Flush();

    //You have to rewind the MemoryStream before copying
    ms.Seek(0, SeekOrigin.Begin);

    using (FileStream fs = new FileStream("output.txt", FileMode.OpenOrCreate))
    {
        ms.CopyTo(fs);
        fs.Flush();
    }
}

此外,由于fs位于using语句中,将在结尾处被处理,因此您不必关闭它。


1
什么也没发生 - 文件没有改变。 - Coding Duchess
2
我更新了代码并进行了修改,你需要使用 Seek(0, SeekOrigin.Begin)。 - Philippe Paré
2
我正在使用 .Net Framework 3.5,所以这可能与此有关,但是我可以使用 Stream.CopyTo(Stream),因为它不存在。相反,我必须使用 Stream.WriteTo(Stream) - MartynJones87
5
你可以使用 ms.Position = 0 来“倒回”流,而不是使用 ms.Seek(0, SeekOrigin.Begin)。 - Davide Dolla
严格来说,fs.Flush() 是多余的,不是吗?因为文件流在被 Dispose() 的时候会自动 Flush。我问这个问题是因为我有一个相关的 bug,但我不相信在我打开文件流的所有地方添加 Flush() 会解决任何问题。 - noio

4
 using (var memoryStream = new MemoryStream())
 {
    ...

     var fileName = $"FileName.xlsx";
     string tempFilePath = Path.Combine(Path.GetTempPath() + fileName );
     using (var fs = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
     {
        memoryStream.WriteTo(fs);
     }

 }

2

//重置流的位置

ms.Position = 0;

//然后将其复制到文件流中

ms.CopyTo(fileStream);

1
没有必要重置流的位置,只需调用 ms.ToArray() 就可以将整个内存流(从零开始)复制到一个数组中。根据文档的描述:“将流内容写入字节数组中,不考虑 Position 属性。” - Ron Beyer

1
问题与您的文件流/内存流无关。问题在于DataContractJsonSerializer是一种选择性序列化器。您需要在myClass上添加[DataMemberAttribute]以将所有需要序列化的属性添加到其中。
[DataContract]
public class myClass
{
     [DataMember]
     public string Foo { get; set; }
}

0

这一行看起来有问题:

ms.Read(ms.ToArray(), 0, (int)ms.Length);

在这个阶段,您不应该需要读取内存流中的任何内容,特别是当您的代码已经编写为将 ms 读入 ms 时。

我非常有信心,只需删除此行即可解决您的问题。


之前我尝试了ms.WriteTo(fs),但结果还是一样的。 - Coding Duchess

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接