简体   繁体   English

在添加到MemoryStream之前,如何检查添加到MemoryStream的结果?

[英]How can I check result of adding to a MemoryStream, before adding to the MemoryStream?

I am creating an XML file using a Memory stream, in the following manner - 我正在以以下方式使用Memory流创建XML文件-

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;

MemoryStream ms = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(ms, settings))
{
    // CREATE XML WITH STATEMENTS LIKE THIS
    writer.WriteStartElement("url", myUrl);
    writer.WriteEndElement();
}

Is there some way to check what the length of the resulting MemoryStream will be, before actually adding the element to the MemoryStream ? 在实际将元素添加到MemoryStream之前,是否有某种方法可以检查生成的MemoryStream的长度?

Something like - 就像是 -

var sizeTotal = ms + (writer.WriteStartElement("url", myUrl);

The purpose of this is so I can check sizeTotal , make sure it's not too big before I write it to the MemoryStream . 这样做的目的是让我可以检查sizeTotal ,确保在将它写入MemoryStream之前不要太大。

I have a size limit of 10MB for the XML file I am generating. 我生成的XML文件的大小限制为10MB。 Could I write to a "temp" stream 1st, check the length, if the sizeTotal is less than 10MB, write to the element to the "real" stream. 我可以先写入“临时”流,检查长度,如果sizeTotal小于10MB,则将元素写入“实际”流。 Else, if the sizeTotal is more than 10MB, I want to not add the element to the stream, generate the XML file, then start a new file. 否则,如果sizeTotal是超过10MB,我想不是元素添加到流,生成XML文件,然后启动一个新的文件。

There's no way I know of to determine how long an element will be before you actually write it. 我无法确定在实际编写元素之前要确定元素的长度。 But you can determine how long the thing was, and then back up if you need to. 但你可以决定的事情有多长,然后备份,如果你需要。 The key is to get the current position of the MemoryStream before you begin the write, and subtract that from the position after writing. 关键是在开始写入之前获取MemoryStream的当前位置,并在写入之后从该位置减去当前位置。 For example: 例如:

using (XmlWriter writer = XmlWriter.Create(ms, settings))
{
    long startPos = ms.Position;
    // write an element
    writer.WriteStartElement("url", myUrl);
    writer.WriteEndElement();
    writer.Flush();  // make sure data is flushed to the stream
    long endPos = ms.Position;

}

So if endPos goes beyond your size limit, you can copy the memory stream from 0 to startPos , and save it. 因此,如果endPos超出大小限制,则可以将内存流从0复制到startPos并保存。 You can then position the stream at 0 and retry your write. 然后,您可以将流置于0,然后重试写入。 Something like: 就像是:

using (XmlWriter writer = XmlWriter.Create(ms, settings))
{
    // write an element
    while (true)
    {
        long startPos = ms.Position;
        writer.WriteStartElement("url", myUrl);
        writer.WriteEndElement();
        writer.Flush();  // make sure data is flushed to the stream
        if (ms.Position < maxSize)
            break;
        // here, copy memory buffer from 0 to startPos and save to disk
        // then, reset position
        ms.Position = 0;
    }

    // write another element
    while (true)
    {
        // same thing, different element
    }

    // make sure to write the final buffer!
}

That's the general idea. 那是一般的想法。 Of course you'd want to make sure you don't go into an infinite loop if a single element exceeds the threshold value. 当然,如果单个元素超出阈值,您将要确保不会陷入无限循环。

Note that I don't address the problem of XML fragments, which this technique will undoubtedly create. 请注意,我没有解决XML片段的问题,该技术无疑会创建该问题。 If you want your individual files to be valid XML, you'll have to keep track of which elements are opened, so when you write the partial file all those elements are closed. 如果要使各个文件为有效的XML,则必须跟踪打开了哪些元素,因此在编写部分文件时,所有这些元素都将关闭。 You'll also need to open those elements when you initialize the memory stream for the next bit. 当您为下一位初始化内存流时,还需要打开这些元素。 You can either do that in place of the ms.Position = 0; 您可以代替ms.Position = 0; , or you can do that when you write the next fragment out. ,也可以在写下下一个片段时执行此操作。

Without knowing more about the larger problem (ie what you're doing with these partial files), I can't make specific recommendations about how to handle it. 如果不了解更大的问题(即您对这些部分文件的处理方式),我将无法就如何处理提出具体建议。

You mean something like this? 你的意思是这样的吗?

var myUrl = "http://www.stackoverflow.com";
var encoding = Encoding.UTF8;

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = encoding;
var SOME_MAX_SIZE_IN_BYTES = 1024;
MemoryStream ms = new MemoryStream();
for(var i=0; i<10; i++)
{
    using (XmlWriter writer = XmlWriter.Create(ms, settings))
    {    
        // CREATE XML WITH STATEMENTS LIKE THIS
        writer.WriteStartElement("url", myUrl);
        writer.WriteEndElement();
        // in order to get a semi-accurate byte count, 
        // you need to force the flush to the underlying stream
        writer.Flush();
        var lengthInBytes = ms.Length;
        if(lengthInBytes > SOME_MAX_SIZE_IN_BYTES)
        {
            Console.WriteLine("TOO BIG!");
            break;
        }
    }
}

var xml = encoding.GetString(ms.ToArray());
Console.WriteLine(xml);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM