使用.NET将日志写入XML文件

7

我正在将日志存储在一个xml文件中...

在传统的直接文本格式方法中,您通常只需要使用openFile...然后使用writeLine方法...

如何像使用文本文件的方法一样,在xml文档结构中添加新条目?


使用一个能够直接完成这种工作的日志库 - JP Alioto
8个回答

4
请使用XmlWriter。
示例代码:
    public class Quote
    {
        public string symbol;
        public double price;
        public double change;
        public int volume;
    }


    public void Run()
    {
        Quote q = new Quote
            {
                symbol = "fff",
                price = 19.86,
                change = 1.23,
                volume = 190393,
                };
        WriteDocument(q);
    }



    public void WriteDocument(Quote q) 
    {
        var settings = new System.Xml.XmlWriterSettings
            {
                OmitXmlDeclaration = true,
                Indent= true
            };

        using (XmlWriter writer = XmlWriter.Create(Console.Out, settings))
        {
            writer.WriteStartElement("Stock");
            writer.WriteAttributeString("Symbol", q.symbol);
            writer.WriteElementString("Price", XmlConvert.ToString(q.price));
            writer.WriteElementString("Change", XmlConvert.ToString(q.change));
            writer.WriteElementString("Volume", XmlConvert.ToString(q.volume));
            writer.WriteEndElement();
        }
    }

示例输出:

<Stock Symbol="fff">
  <Price>19.86</Price>
  <Change>1.23</Change>
  <Volume>190393</Volume>
</Stock>

请参阅使用XmlWriter编写以获得更多信息。


代码相关内容翻译:没有实现using块并且没有使用XmlWriter.Create,返回-1。 - John Saunders
如果你到达Close,它意味着没有发生异常。即使发生异常,using也会调用Dispose。你正在接近成功。我很快就会给你点赞的,期待你的精彩表现。 - John Saunders

2
写XML格式的日志文件有一个问题,就是你不能简单地将行添加到文件末尾,因为最后一行必须有一个关闭根元素(以使XML有效)。Filip De Vos在博客文章中提供了一个相当不错的解决方案:高性能写入XML日志文件。基本上,您需要使用XML-include将两个XML文件链接在一起:头文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log [
<!ENTITY loglines SYSTEM "loglines.xml">
]>
<log>
&loglines;
</log>

行文件(在本例中,命名为loglines.xml):

<logline date="2007-07-01 13:56:04.313" text="start process" />
<logline date="2007-07-01 13:56:25.837" text="do something" />
<logline date="2007-07-01 13:56:25.853" text="the end" />

您可以将新行附加到“行文件”,但(大多数)XML解析器将能够打开头文件并正确读取这些行。

Filip指出:这个XML不会被地球上的每个XML解析器正确解析。但是我使用过的所有解析器都能正确处理它。


1

最大的区别在于你对日志数据的思考方式。在纯文本文件中,你只是添加新行。然而,XML是一种树形结构,你需要像处理树形结构一样去思考。你要添加的可能是另一个节点,例如:

<log>
   <time>12:30:03 PST</time>
   <user>joe</user>
   <action>login</action>
<log>

因为它是一棵树,你需要问的是你要将这个新节点添加到哪个父节点。通常这都在你的DTD中定义(也就是你如何定义数据结构)。希望这比仅仅使用哪个库更有帮助,因为一旦你理解了这个原则,库的接口应该会更加清晰明了。


1

非常抱歉回复旧的帖子。我之前开发了相同的代码,现在我想分享我的完整代码,该日志记录器将日志数据按日期保存为XML文件。

日志记录器类代码

using System.IO;
using System.Xml;
using System.Threading;

public class BBALogger
    {
        public enum MsgType
        {
            Error ,
            Info 
        }

        public static BBALogger Instance
        {
            get
            {
                if (_Instance == null)
                {
                    lock (_SyncRoot)
                    {
                        if (_Instance == null)
                            _Instance = new BBALogger();
                    }
                }
                return _Instance;
            }
        }

        private static BBALogger _Instance;
        private static object _SyncRoot = new Object();
        private static ReaderWriterLockSlim _readWriteLock = new ReaderWriterLockSlim();

        private BBALogger()
        {
            LogFileName = DateTime.Now.ToString("dd-MM-yyyy");
            LogFileExtension = ".xml";
            LogPath= Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Log";
        }

        public StreamWriter Writer { get; set; }

        public string LogPath { get; set; }

        public string LogFileName { get; set; }

        public string LogFileExtension { get; set; }

        public string LogFile { get { return LogFileName + LogFileExtension; } }

        public string LogFullPath { get { return Path.Combine(LogPath, LogFile); } }

        public bool LogExists { get { return File.Exists(LogFullPath); } }

        public void WriteToLog(String inLogMessage, MsgType msgtype)
        {
            _readWriteLock.EnterWriteLock();
            try
            {
                LogFileName = DateTime.Now.ToString("dd-MM-yyyy");

                if (!Directory.Exists(LogPath))
                {
                    Directory.CreateDirectory(LogPath);
                }

                var settings = new System.Xml.XmlWriterSettings
                {
                    OmitXmlDeclaration = true,
                    Indent = true
                };

                StringBuilder sbuilder = new StringBuilder();
                using (StringWriter sw = new StringWriter(sbuilder))
                {
                    using (XmlWriter w = XmlWriter.Create(sw, settings))
                    {
                        w.WriteStartElement("LogInfo");
                        w.WriteElementString("Time", DateTime.Now.ToString());
                        if (msgtype == MsgType.Error)
                            w.WriteElementString("Error", inLogMessage);
                        else if (msgtype == MsgType.Info)
                            w.WriteElementString("Info", inLogMessage);

                        w.WriteEndElement();
                    }
                }
                using (StreamWriter Writer = new StreamWriter(LogFullPath, true, Encoding.UTF8))
                {
                    Writer.WriteLine(sbuilder.ToString());
                }
            }
            catch (Exception ex)
            {

            }
            finally
            {
                _readWriteLock.ExitWriteLock();
            }
        }

        public static void Write(String inLogMessage, MsgType msgtype)
        {
            Instance.WriteToLog(inLogMessage, msgtype);
        }
    }

使用这种方式进行调用或使用。
    BBALogger.Write("pp1", BBALogger.MsgType.Error);
    BBALogger.Write("pp2", BBALogger.MsgType.Error);
    BBALogger.Write("pp3", BBALogger.MsgType.Info);
    MessageBox.Show("done");

愿我的代码能帮助你和其他人 :)


另一个好的记录器网址 http://blog.bondigeek.com/2011/09/08/a-simple-c-thread-safe-logging-class/ - Mou

1

0

如果没有更多关于你在做什么的信息,我只能提供一些基本建议。

大多数 XML 对象都有一个叫做“AppendChild”的方法。你可以使用这个方法来添加一个包含日志注释的新节点。这个节点将会出现在项目列表的末尾。你需要使用所有日志节点所在的父元素作为调用对象。

希望这可以帮到你。


0

XML需要一个文档元素(基本上是开始和结束文档的顶级标签)。

这意味着一个格式良好的XML文档需要有一个开头和结尾,这对于日志来说并不太适合,因为日志的当前“结尾”是不断扩展的。

除非您正在编写自包含日志批处理,其中您将要记录的所有内容都在短时间内写入一个文件中,否则我建议您考虑使用其他东西而不是XML。

如果您正在编写完成工作单元的日志或者不需要在整个过程完成之前进行检查的日志,则可以使用您的方法 - 只需打开文件,写入日志行,完成工作单元时关闭文件即可。


0

链接失效,网站已不存在。 - Zaid Masud

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接