按照加载巨大XML文件的进度

时间:2009-12-31 09:35:38

标签: c# .net xml

我尝试在dotnet(C#,framework 3.5 SP1)中跟踪大型XML文件(我不是这些文件的提供者)的加载进度:通过网络文件共享从1 MB到300 MB。

我使用XmlReader进行加载,而不是直接使用XmlDocument.Load方法来加速加载过程。

顺便说一句,我在互联网/文档上找不到如何遵循此加载进度:似乎没有代理/事件存在。有没有办法执行这项任务?具有用于XML保存目的的功能可能是一件好事。

由于

3 个答案:

答案 0 :(得分:13)

假设你正在阅读一个流,这里有一个(非完美的)如何做的例子...... 基本上,ProgressStreamWrapper包装文件流并在Position更改时引发事件。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Reading big file...");

        FileStream fileStream = File.OpenRead("c:\\temp\\bigfile.xml");
        ProgressStreamWrapper progressStreamWrapper = new ProgressStreamWrapper(fileStream);
        progressStreamWrapper.PositionChanged += (o, ea) => Console.WriteLine((double) progressStreamWrapper.Position / progressStreamWrapper.Length * 100 + "% complete");
        XmlReader xmlReader = XmlReader.Create(progressStreamWrapper);

        while (xmlReader.Read())
        {
            //read the xml document
        }

        Console.WriteLine("DONE");
        Console.ReadLine();
    }
}


public class ProgressStreamWrapper : Stream, IDisposable
{
    public ProgressStreamWrapper(Stream innerStream)
    {
        InnerStream = innerStream;
    }

    public Stream InnerStream { get; private set; }

    public override void Close()
    {
        InnerStream.Close();
    }

    void IDisposable.Dispose()
    {
        base.Dispose();
        InnerStream.Dispose();
    }

    public override void Flush()
    {
        InnerStream.Flush();
    }

    public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
    {
        return InnerStream.BeginRead(buffer, offset, count, callback, state);
    }

    public override int EndRead(IAsyncResult asyncResult)
    {
        int endRead = InnerStream.EndRead(asyncResult);
        OnPositionChanged();
        return endRead;
    }

    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
    {
        return InnerStream.BeginWrite(buffer, offset, count, callback, state);
    }

    public override void EndWrite(IAsyncResult asyncResult)
    {
        InnerStream.EndWrite(asyncResult);
        OnPositionChanged(); ;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        long seek = InnerStream.Seek(offset, origin);
        OnPositionChanged();
        return seek;
    }

    public override void SetLength(long value)
    {
        InnerStream.SetLength(value);
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        int read = InnerStream.Read(buffer, offset, count);
        OnPositionChanged();
        return read;
    }

    public override int ReadByte()
    {
        int readByte = InnerStream.ReadByte();
        OnPositionChanged();
        return readByte;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        InnerStream.Write(buffer, offset, count);
        OnPositionChanged();
    }

    public override void WriteByte(byte value)
    {
        InnerStream.WriteByte(value);
        OnPositionChanged();
    }

    public override bool CanRead
    {
        get { return InnerStream.CanRead; }
    }

    public override bool CanSeek
    {
        get { return InnerStream.CanSeek; }
    }

    public override bool CanTimeout
    {
        get { return InnerStream.CanTimeout; }
    }

    public override bool CanWrite
    {
        get { return InnerStream.CanWrite; }
    }

    public override long Length
    {
        get { return InnerStream.Length; }
    }

    public override long Position
    {
        get { return InnerStream.Position; }
        set
        {
            InnerStream.Position = value;
            OnPositionChanged();
        }
    }

    public event EventHandler PositionChanged;

    protected virtual void OnPositionChanged()
    {
        if (PositionChanged != null)
        {
            PositionChanged(this, EventArgs.Empty);
        }
    }

    public override int ReadTimeout
    {
        get { return InnerStream.ReadTimeout; }
        set { InnerStream.ReadTimeout = value; }
    }

    public override int WriteTimeout
    {
        get { return InnerStream.WriteTimeout; }
        set { InnerStream.WriteTimeout = value; }
    }
}

答案 1 :(得分:2)

内置装载机并不多;但是,您可以编写拦截流 - 从此流加载文档,并通过事件公开Position?即以Read方法(间隔)提出一个事件?


这是一个支持读写期间更新的示例:

using System;
using System.IO;
using System.Xml;
class ChattyStream : Stream
{
    private Stream baseStream;
    public ChattyStream(Stream baseStream)
    {
        if (baseStream == null) throw new ArgumentNullException("baseStream");
        this.baseStream = baseStream;
        updateInterval = 1000;
    }
    public event EventHandler ProgressChanged;
    protected virtual void OnProgressChanged()
    {
        var handler = ProgressChanged;
        if (handler != null) handler(this, EventArgs.Empty);
    }
    private void CheckDisposed()
    {
        if (baseStream == null) throw new ObjectDisposedException(GetType().Name);
    }
    protected Stream BaseStream
    {
        get { CheckDisposed(); return baseStream; }
    }
    int pos, updateInterval;
    public int UpdateInterval
    {
        get { return updateInterval; }
        set
        {
            if (value <= 0) throw new ArgumentOutOfRangeException("value");
            updateInterval = value;
        }
    }

    protected void Increment(int value)
    {
        if (value > 0)
        {
            pos += value;
            if (pos >= updateInterval)
            {
                OnProgressChanged();
                pos = pos % updateInterval;
            }
        }
    }
    public override int Read(byte[] buffer, int offset, int count)
    {
        int result = BaseStream.Read(buffer, offset, count);
        Increment(result);
        return result;
    }
    public override void Write(byte[] buffer, int offset, int count)
    {
        BaseStream.Write(buffer, offset, count);
        Increment(count);
    }
    public override void SetLength(long value)
    {
        BaseStream.SetLength(value);
    }
    public override void Flush()
    {
        BaseStream.Flush();
    }
    public override long Position
    {
        get { return BaseStream.Position; }
        set { BaseStream.Position = value; }
    }
    public override long Seek(long offset, SeekOrigin origin)
    {
        return BaseStream.Seek(offset, origin);
    }
    public override long Length
    {
        get { return BaseStream.Length; }
    }
    public override bool CanWrite
    {
        get { return BaseStream.CanWrite; }
    }
    public override bool CanRead
    {
        get { return BaseStream.CanRead; }
    }
    public override bool CanSeek
    {
        get { return BaseStream.CanSeek; }
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing && baseStream != null)
        {
            baseStream.Dispose();
        }
        baseStream = null;
        base.Dispose(disposing);
    }
    public override void Close()
    {
        if (baseStream != null) baseStream.Close();
        base.Close();
    }
    public override int ReadByte()
    {
        int val = BaseStream.ReadByte();
        if (val >= 0) Increment(1);
        return val;
    }
    public override void WriteByte(byte value)
    {
        BaseStream.WriteByte(value);
        Increment(1);
    }

}
static class Program
{
    static void Main()
    {
        /* invent some big data */
        const string path = "bigfile";
        if (File.Exists(path)) File.Delete(path);
        using (var chatty = new ChattyStream(File.Create(path)))
        {
            chatty.ProgressChanged += delegate
            {
                Console.WriteLine("Writing: " + chatty.Position);
            };
            using (var writer = XmlWriter.Create(chatty))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("xml");
                for (int i = 0; i < 50000; i++)
                {
                    writer.WriteElementString("add", i.ToString());
                }
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
            chatty.Close();
        }


        /* read it */

        using (var chatty = new ChattyStream(File.OpenRead("bigfile")))
        {
            chatty.ProgressChanged += delegate
            {
                Console.WriteLine("Reading: " + chatty.Position);
            };

            // now read "chatty" with **any** API; XmlReader, XmlDocument, XDocument, etc
            XmlDocument doc = new XmlDocument();
            doc.Load(chatty);
        }
    }
}

答案 2 :(得分:-1)

如何使用DataSet.Read()?

,或者

// Create the document.
        XmlDocument doc = new XmlDocument();
        doc.Load(file);

        // Loop through all the nodes, and create the list of Product objects .
        List<Product> products = new List<Product>();

        foreach (XmlElement element in doc.DocumentElement.ChildNodes)
        {
            Product newProduct = new Product();
            newProduct.ID = Int32.Parse(element.GetAttribute("ID"));
            newProduct.Name = element.GetAttribute("Name");

            // If there were more than one child node, you would probably use
            // another For Each loop here and move through the
            // Element.ChildNodes collection.
            newProduct.Price = Decimal.Parse(element.ChildNodes[0].InnerText);

            products.Add(newProduct);
        }