2009-12-31 26 views
7

Tôi cố gắng theo dõi tiến độ tải của các tệp XML lớn (tôi không phải là nhà cung cấp các tệp này) trong dotnet (C#, khung 3.5 SP1): từ 1 MB đến 300 MB trên chia sẻ tệp mạng.theo tiến trình tải các tệp XML lớn

Tôi sử dụng XmlReader cho mục đích tải thay vì phương pháp XmlDocument.Load trực tiếp để tăng tốc quá trình tải.

Bằng cách tôi tìm thấy hư không trên internet/tài liệu về cách theo dõi tiến độ tải này: không có đại biểu/sự kiện nào dường như tồn tại. Có cách nào để thực hiện nhiệm vụ này không? Có loại chức năng cho mục đích tiết kiệm XML có thể là một điều tốt đẹp để có.

Cảm ơn

+0

Bạn đang tải những tệp này ở đâu, trong DOM/Cơ sở dữ liệu hoặc cái gì khác? Bạn đang đọc và xử lý chúng bằng nút hay tải chúng vào bộ nhớ? – A9S6

+0

Tôi giả sử tôi quên đặt một số thông tin: Tôi tải các tệp XML này cho một API (Tôi có nguồn, nhưng tôi không muốn chỉnh sửa logic/phân tích cú pháp) phân tích cú pháp tệp (chủ yếu với Xpath). API này chấp nhận trong XML param một đường dẫn đến một tệp XML (và sử dụng XmlReader) hoặc một Stream. Tôi không thực sự quan tâm đến quá trình phân tích cú pháp nhanh chóng, chỉ tập trung vào quá trình tải trong bộ nhớ. – camous

+0

XmlReader không hỗ trợ XPath và chỉ cung cấp truy cập nối tiếp ... nếu bạn cần xử lý phức tạp hơn, bạn có thể muốn sử dụng XPathNaviator hoặc nếu việc sử dụng bộ nhớ là quan trọng, hãy thử vtd-xml –

Trả lời

13

Giả sử bạn đang đọc từ một dòng suối ở đây là một (không hoàn hảo) ví dụ về làm thế nào để làm điều đó ... Về cơ bản, ProgressStreamWrapper bao bọc luồng tệp và tăng sự kiện bất cứ khi nào Vị trí bị thay đổi.

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; } 
    } 
} 
+0

Có, tôi có thể cung cấp như API param một Stream vì vậy tôi sẽ tìm đến loại giải pháp (sự kiện PositionChanged). Sẽ cập nhật ngày hôm nay. – camous

+0

Tôi nghĩ rằng chúng tôi đã có cùng một ý tưởng, nhưng mã của bạn đã ở đây trước tiên, vì vậy một +1 nhất định ;-p –

-1

Cách sử dụng DataSet.Read()?

hay,

// 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); 
     } 
+0

Về cơ bản, tôi cố gắng tập trung vào cơ chế tải chứ không phải cơ chế phân tích cú pháp: quá trình phân tích cú pháp được thực hiện bởi một API bên ngoài. Trong ví dụ của bạn, 'doc.Load (file);' sẽ tải tệp XML tổng thể ở bước này và chỉ tiếp tục khi tệp sẽ được tải trong bộ nhớ. – camous

2

Với bộ tải sẵn không có nhiều; Tuy nhiên, bạn có thể viết luồng chặn - tải tài liệu của mình từ luồng này và hiển thị các sự kiện Position qua sự kiện? tức là tăng sự kiện theo phương pháp Read (trong khoảng thời gian)?


Dưới đây là một ví dụ mà hỗ trợ cập nhật trong suốt cả đọc và viết:

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); 
     } 
    } 
} 
Các vấn đề liên quan