Проверьте размер вывода с помощью .NET XmlTextWriter - PullRequest
1 голос
/ 22 февраля 2010

Мне нужно сгенерировать файл XML, и мне нужно вставить в него как можно больше данных, НО существует ограничение на размер файла. Поэтому мне нужно продолжать вставлять данные, пока что-то не говорит больше. Как определить размер файла XML без повторной записи его в файл?

Ответы [ 3 ]

2 голосов
/ 22 февраля 2010

Я согласен с Джоном Сондерсом. Вот некоторый код, который в основном будет делать то, о чем он говорит, но как XmlSerializer, за исключением FileStream и использует MemoryStream в качестве промежуточного хранилища. Хотя может быть более эффективно расширить поток.

public class PartitionedXmlSerializer<TObj>
{
    private readonly int _fileSizeLimit;

    public PartitionedXmlSerializer(int fileSizeLimit)
    {
        _fileSizeLimit = fileSizeLimit;
    }

    public void Serialize(string filenameBase, TObj obj)
    {
        using (var memoryStream = new MemoryStream())
        {
            // serialize the object in the memory stream
            using (var xmlWriter = XmlWriter.Create(memoryStream))
                new XmlSerializer(typeof(TObj))
                    .Serialize(xmlWriter, obj);

            memoryStream.Seek(0, SeekOrigin.Begin);

            var extensionFormat = GetExtensionFormat(memoryStream.Length);

            var buffer = new char[_fileSizeLimit];

            var i = 0;
            // split the stream into files
            using (var streamReader = new StreamReader(memoryStream))
            {
                int readLength;
                while ((readLength = streamReader.Read(buffer, 0, _fileSizeLimit)) > 0)
                {
                    var filename 
                        = Path.ChangeExtension(filenameBase, 
                            string.Format(extensionFormat, i++));
                    using (var fileStream = new StreamWriter(filename))
                        fileStream.Write(buffer, 0, readLength);
                }
            }
        }
    }

    /// <summary>
    /// Gets the a file extension formatter based on the 
    /// <param name="fileLength">length of the file</param> 
    /// and the max file length
    /// </summary>
    private string GetExtensionFormat(long fileLength)
    {
        var numFiles = fileLength / _fileSizeLimit;
        var extensionLength = Math.Ceiling(Math.Log10(numFiles));
        var zeros = string.Empty;
        for (var j = 0; j < extensionLength; j++)
        {
            zeros += "0";
        }
        return string.Format("xml.part{{0:{0}}}", zeros);
    }
}

Чтобы использовать его, вы должны инициализировать его с максимальной длиной файла, а затем сериализовать, используя путь к базовому файлу, а затем объект.

public class MyType
{
    public int MyInt;
    public string MyString;
}

public void Test()
{
    var myObj = new MyType { MyInt = 42, 
                             MyString = "hello there this is my string" };
    new PartitionedXmlSerializer<MyType>(2)
        .Serialize("myFilename", myObj);
}

В этом конкретном примере будет сгенерирован xml-файл, разбитый на

myFilename.xml.part001
myFilename.xml.part002
myFilename.xml.part003
...
myFilename.xml.part110
1 голос
/ 22 февраля 2010

Как правило, вы не можете разбивать документы XML в произвольных местах, даже если вы закрываете все открытые теги.

Однако, если вам нужно разделить XML-документ на несколько файлов, каждый из которых имеет размер не более определенного размера, то вам следует создать собственный подтип класса Stream. Этот класс "PartitionedFileStream" может записывать в конкретный файл до предела размера, затем создавать новый файл и записывать в этот файл до предела размера и т. Д.

В результате у вас останется несколько файлов, которые при объединении образуют действительный документ XML.


В общем случае закрывающие теги работать не будут. Рассмотрим формат XML, который должен содержать один элемент A, за которым следует один элемент B. Если вы закрыли теги после записи элемента A, то у вас нет действительного документа - вам нужно иметь элемент B.

Однако в конкретном случае простого файла карты сайта можно просто закрыть теги.

0 голосов
/ 22 февраля 2010

Вы можете запросить у XmlTextWriter его BaseStream и проверить его Position. Как указал другой, вам может понадобиться зарезервировать запас, чтобы правильно закрыть Xml.

...