C# C语言中的文件大小限制或限制#

C# C语言中的文件大小限制或限制#,c#,file-io,filesize,C#,File Io,Filesize,我想从一个包含大量数据的对象(包含嵌套集合)生成XML文件。 但是XML有一个限制,它不能超过50MB using (XmlWriter writer = XmlWriter.Create("YourFilePath")) { writer.WriteStartDocument(); writer.WriteStartElement("Root"); for (int i = 0; i < 1000000; i++) //Write one million no

我想从一个包含大量数据的对象(包含嵌套集合)生成XML文件。 但是XML有一个限制,它不能超过50MB

using (XmlWriter writer = XmlWriter.Create("YourFilePath"))
{
    writer.WriteStartDocument();

    writer.WriteStartElement("Root");

    for (int i = 0; i < 1000000; i++) //Write one million nodes.
    {
        writer.WriteStartElement("Root");
        writer.WriteAttributeString("value", "Value #" + i.ToString());
        writer.WriteString("Inner Text #" + i.ToString());
        writer.WriteEndElement();
    }
    writer.WriteEndElement();

    writer.WriteEndDocument();
}
有什么好办法吗


更新:速度并不重要,主要是将每个文件分成50MB

您是否考虑过将XML文件写成字符串,而不是使用.NET中的XML支持

我当时正在将大约10GB的数据写入XML,因为这是工具使用数据的唯一方式

我遇到过这样的问题,但是我的XML非常简单,我只使用了一个TextWriter和嵌套for循环来编写XML


工作很有魅力,而且速度比XML对象快得多。

您可以使用XmlWriterXDocument毫无问题地编写大型XML文件

这里是一个示例。本例在不到5秒内生成一个63MB的xml文件。对于本例,我使用类XmlWriter

using (XmlWriter writer = XmlWriter.Create("YourFilePath"))
{
    writer.WriteStartDocument();

    writer.WriteStartElement("Root");

    for (int i = 0; i < 1000000; i++) //Write one million nodes.
    {
        writer.WriteStartElement("Root");
        writer.WriteAttributeString("value", "Value #" + i.ToString());
        writer.WriteString("Inner Text #" + i.ToString());
        writer.WriteEndElement();
    }
    writer.WriteEndElement();

    writer.WriteEndDocument();
}
使用(XmlWriter=XmlWriter.Create(“您的文件路径”))
{
writer.WriteStartDocument();
writer.writeStarteElement(“根”);
对于(int i=0;i<1000000;i++)//写入一百万个节点。
{
writer.writeStarteElement(“根”);
WriteAttributeString(“value”,“value#”+i.ToString());
writer.WriteString(“内部文本”#“+i.ToString());
writer.writeedelement();
}
writer.writeedelement();
writer.WriteEndDocument();
}

在我的工作中遇到了类似的要求。我的最大努力(直观、易于实现、相对性能)如下所示。我基本上使用
XmlWriter
编写,监视底层流。当它超过我的文件大小限制时,我完成当前Xml片段,保存文件,关闭流

然后在第二步中,我将完整的DOM加载到内存中,然后迭代地删除节点并保存文档,直到它达到可接受的大小

比如说

// arbitrary limit of 10MB
long FileSizeLimit = 10*1024*1024;

// open file stream to monitor file size
using (FileStream file = new FileStream("some.data.xml", FileMode.Create))
using (XmlWriter writer = XmlWriter.Create(file))
{
    writer.WriteStartElement("root");

    // while not greater than FileSizeLimit
    for (; file.Length < FileSizeLimit; )
    {
        // write contents
        writer.WriteElementString(
            "data", 
            string.Format("{0}/{0}/{0}/{0}/{0}", Guid.NewGuid()));
    }

    // complete fragment; this is the trickiest part, 
    // since a complex document may have an arbitrarily
    // long tail, and cannot be known during file size
    // sampling above
    writer.WriteEndElement();
    writer.Flush();
}

// iteratively reduce document size
// NOTE: XDocument will load full DOM into memory
XDocument document = XDocument.Load("some.data.xml");
XElement root = document.Element("root");
for (; new FileInfo("some.data.xml").Length > FileSizeLimit; )
{
    root.LastNode.Remove();
    document.Save("some.data.xml");
}
以及执行修剪的方法(不是扩展方法,因为扩展任何参数类型都有点不明确)

//将xml文件修剪为指定的文件大小。通过
//计算“受害者候选者”的数量,然后迭代
//一次修剪一个候选对象,直到结果
//文件大小刚好小于所需的限制。不
/考虑嵌套的受害者候选人。
公共静态void TrimXmlFile(字符串文件名、长大小、字符串trimNodeName)
{
long fileSize=新文件信息(filename).Length;
长工作节点计数=0;
//计算xml中受害元素的数量
如果(文件大小>大小)
{
XmlReader countReader=XmlReader.Create(文件名);
对于(;countReader.Read();)
{
if(countReader.NodeType==XmlNodeType.Element&&
countReader.Name==trimNodeName)
{
workNodeCount++;
countReader.Skip();
}
}
countReader.Close();
}
//如果大于所需的文件大小,则至少有
//一名受害者候选人
字符串workFilename=filename+“.work”;
对于(;
文件大小>大小和工作节点计数>0;
fileSize=新文件信息(filename).Length)
{
工作节点计数--;
使用(FileStream readFile=newfilestream(filename,FileMode.Open))
使用(FileStream writeFile=new FileStream)(
工作文件名,
FileMode.Create)
{
XmlReader=XmlReader.Create(readFile);
XmlWriter=XmlWriter.Create(writeFile);
长j=0;
bool hasAlreadyRead=false;
for(;(hasAlreadyRead)| | reader.Read();)
{
//如果节点是受害者节点
if(reader.NodeType==XmlNodeType.Element&&
reader.Name==trimNodeName)
{
//如果我们没有超过这个迭代的
//保留节点
如果(j=工作节点计数)
{
reader.ReadToNextSibling(trimNodeName);
}
hasAlreadyRead=true;
}
其他的
{
//我们应该保留的其他一些xml内容
writersallownode(reader);
hasAlreadyRead=false;
}
}
writer.Flush();
}
File.Copy(workFilename,filename,true);
}
删除(工作文件名);
}

如果Xml包含空格格式,则最后一个剩余的受害者节点和结束容器元素标记之间的任何空格都将丢失。这可以通过修改skip子句(将
j++
语句移到skip之后)来缓解,但最终会出现额外的空白。上述解决方案生成源文件的最小文件大小副本。

一切都比xml对象快;)我已经使用这种方法编写/读取了数千GB的xml文件,效果很好。为了获得额外的积分,您可以通过GzipStream将其连接起来,以压缩该文件……您将如何处理其余部分?您的输出文件是什么样子的?如果将其拆分为50mb文件,您会遇到什么问题?请参考
// trims xml file to specified file size. does so by 
// counting number of "victim candidates" and then iteratively
// trimming these candidates one at a time until resultant
// file size is just less than desired limit. does not
// consider nested victim candidates.
public static void TrimXmlFile(string filename, long size, string trimNodeName)
{
    long fileSize = new FileInfo(filename).Length;
    long workNodeCount = 0;

    // count number of victim elements in xml
    if (fileSize > size)
    {
        XmlReader countReader = XmlReader.Create(filename);
        for (; countReader.Read(); )
        {
            if (countReader.NodeType == XmlNodeType.Element && 
                countReader.Name == trimNodeName)
            {
                workNodeCount++;
                countReader.Skip();
            }
        }
        countReader.Close();
    }

    // if greater than desired file size, and there is at least
    // one victim candidate
    string workFilename = filename+".work";
    for (; 
        fileSize > size && workNodeCount > 0; 
        fileSize = new FileInfo(filename).Length)
    {
        workNodeCount--;
        using (FileStream readFile = new FileStream(filename, FileMode.Open))
        using (FileStream writeFile = new FileStream(
            workFilename, 
            FileMode.Create))
        {
            XmlReader reader = XmlReader.Create(readFile);
            XmlWriter writer = XmlWriter.Create(writeFile);

            long j = 0;
            bool hasAlreadyRead = false;
            for (; (hasAlreadyRead) || reader.Read(); )
            {

                // if node is a victim node
                if (reader.NodeType == XmlNodeType.Element && 
                    reader.Name == trimNodeName)
                {
                    // if we have not surpassed this iteration's
                    // allowance, preserve node
                    if (j < workNodeCount)
                    {
                        writer.WriteNode(reader, true);
                    }
                    j++;

                    // if we have exceeded this iteration's
                    // allowance, trim node (and whitespace)
                    if (j >= workNodeCount)
                    {
                        reader.ReadToNextSibling(trimNodeName);
                    }
                    hasAlreadyRead = true;
                }
                else
                {
                    // some other xml content we should preserve
                    writer.WriteShallowNode(reader);
                    hasAlreadyRead = false;
                }
            }
            writer.Flush();
        }
        File.Copy(workFilename, filename, true);
    }
    File.Delete(workFilename);
}