我尝试在dotnet(C#,framework 3.5 SP1)中跟踪大型XML文件(我不是这些文件的提供者)的加载进度:通过网络文件共享从1 MB到300 MB。
我使用XmlReader进行加载,而不是直接使用XmlDocument.Load方法来加速加载过程。
顺便说一句,我在互联网/文档上找不到如何遵循此加载进度:似乎没有代理/事件存在。有没有办法执行这项任务?具有用于XML保存目的的功能可能是一件好事。
由于
答案 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);
}