首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

大型 XML 日誌高效寫入方案:外部實體引用 + XmlWriter 流式寫入避免記憶體暴漲

     編輯:關於ASP.NET

大量日誌直接 XmlDocument.Load 會耗盡記憶體。本文採用 DOCTYPE 外部實體引用 + XmlWriter 追加寫入 方案:主 XML 僅保留結構與實體引用,實際內容寫入獨立片段檔案,實現 O(1) 記憶體寫入。

架構設計

  • 主日誌檔:XmlLogFile-20110220000120.xml,包含 DOCTYPE 實體宣告與根結構。
  • 內容片段檔:XmlLogContentFile-20110220000120.txt,純 XML 片段,持續追加。
  • 關聯機制:`` + `&Locations;` 占位符。

檔案結構圖

主檔初始化(僅一次)

private static void InitXmlFile(string xmlLogFilePath, string contentFileName, string entityRef) {
    var docType = $@"
<!DOCTYPE XmlLogFile [
  <!ENTITY {entityRef} SYSTEM ""{contentFileName}""
]>";
    var settings = new XmlWriterSettings { Indent = true };
    using (var writer = XmlWriter.Create(xmlLogFilePath, settings)) {
        writer.WriteStartDocument();
        writer.WriteRaw(docType); // 寫入 DOCTYPE 宣告
        writer.WriteStartElement("XmlLogFile");
        writer.WriteStartElement("XmlLogContent");
        writer.WriteEntityRef(entityRef); // 寫入 &Locations;
        writer.WriteEndElement(); // XmlLogContent
        writer.WriteEndElement(); // XmlLogFile
    }
}
// 生成內容:
// <?xml version="1.0" encoding="utf-8"?>
// <!DOCTYPE XmlLogFile [ <!ENTITY Locations SYSTEM "XmlLogContentFile-...txt"> ]>
// <XmlLogFile><XmlLogContent>&Locations;</XmlLogContent></XmlLogFile>

日誌寫入:僅追加片段檔

public static void Log(string contentFilePath, object logEntity) {
    var settings = new XmlWriterSettings { 
        Indent = true, 
        ConformanceLevel = ConformanceLevel.Fragment // 關鍵:片段模式,無 XML 宣告
    };
    using (var writer = XmlWriter.Create(contentFilePath, settings)) {
        // 選項 A:序列化物件
        new XmlSerializer(logEntity.GetType()).Serialize(writer, logEntity);
        // 選項 B:手寫元素
        // writer.WriteStartElement("LogEntry");
        // writer.WriteElementString("Time", DateTime.Now.ToString("o"));
        // writer.WriteElementString("Message", msg);
        // writer.WriteEndElement();
    }
}

讀取合併視圖

// 解析時自動展開實體引用
var doc = new XmlDocument { XmlResolver = new XmlUrlResolver() };
doc.Load(xmlLogFilePath);
var content = doc.SelectSingleNode("/XmlLogFile/XmlLogContent").InnerXml; // 已包含片段內容
// 或使用 XDocument (需設定 LoadOptions.SetLineInfo)
var xdoc = XDocument.Load(xmlLogFilePath, LoadOptions.SetLineInfo);

方案優勢對比

方案記憶體寫入效能讀取效能適用場景
XmlDocument 全量載入O(N) 全量佔用慢(每次重寫)快(記憶體樹)小檔案、頻繁查詢
XmlWriter 覆寫整檔O(N) 需讀取舊內容慢快中等檔案、低頻寫入
外部實體 + 片段追加O(1) 僅片段緩衝極快(僅追加)中(需展開實體)大型日誌、高頻寫入、長期保存
資料庫/NoSQL由引擎管理快快(索引)結構化查詢、多維分析

生產環境注意事項

  • 實體引用安全性:XmlResolver 可能導致 XXE 攻擊,解析時務必禁用外部實體 或使用安全解析器。
  • 檔案輪轉:按日期/大小切分主檔與片段檔,避免單檔過大。
  • 編碼一致性:主檔與片段檔均使用 UTF-8,避免實體展開亂碼。
  • 併發寫入:片段檔追加需鎖(lock/FileShare)或採用單寫入器隊列。
  • 備份策略:片段檔為純文本,易於壓縮、異地備份、日誌分析工具(Logstash/Fluentd)採集。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved