[.NET][C#]避免使用System.IO.File.AppendAllText寫出大型文字檔案

今天加班幫同事抓報表效能問題,調整報表元件後,程式執行時間從14分鐘降成1分鐘,除了寫法上本身的效能差異外,還意外發現防毒軟體來湊腳,最後從微軟connect也發現2年前有一篇討論串提到AppendAlltext及防毒軟體,來筆記紀念今天。

一開始方向往C#字串串接、資料物件的操作下手,幾次調整下來,發現同事的筆電每次執行時CPU就飆高,後來改寫StreamWriter後大幅降低時間及CPU。

進一步比較AppendAllText執行時,CPU飆高時也包含到防毒軟體的活動,發現古怪。

 

AppendAllText vs StreamWriter效能比較

試著用System.IO.FileStream及System.IO.StreamWriter改寫System.IO.File.AppendAllText,從單元測試時就發現效能差異很大。

測試寫入10,000筆文字檔案,1分鐘是System.IO.File.AppendAllText,43毫秒是調校後的寫法,差距1,756倍

印象中有差,但1萬筆就能差這麼多?

 


防毒軟體的活動

執行對照組的當下,防毒軟體很盡責的防衛我們家(防毒程式在同事的筆電CPU使用率更高,同事是用多執行緒寫)

執行實驗組的當下,防毒軟體幾乎沒有活動

有興趣的朋友可以試試用processmonitor工具偵測,可以觀察程式執行時對檔案的頻繁活動以及防毒軟體活動。

 


單元測試程式碼

筆記測試程式碼:

[TestMethod]
public void TestMethod1()
{
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();

    for (int i = 0; i < 10000; i++)
    {
        System.IO.File.AppendAllText(@"C:\temp\A.txt", " @@ ", Encoding.Default);
    }

    TimeSpan ts = stopWatch.Elapsed;
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
    ts.Hours, ts.Minutes, ts.Seconds,
    ts.Milliseconds / 10);
    Console.WriteLine("RunTime " + elapsedTime);
}


[TestMethod]
public void TestMethod2()
{
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();

    List<string> ls = new List<string>();
    for (int i = 0; i < 10000; i++)
    {
        ls.Add(" @@ ");
    }

    using (FileStream fs = new FileStream(@"C:\temp\B.txt", FileMode.Create, FileAccess.Write, FileShare.None))
    {
        using (StreamWriter srOutFile = new StreamWriter(fs, Encoding.Default))
        {
            foreach (string s in ls)
            {
                srOutFile.Write(s);
                srOutFile.Flush();
            }
            srOutFile.Close();
        }
    }
    TimeSpan ts = stopWatch.Elapsed;
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
    ts.Hours, ts.Minutes, ts.Seconds,
    ts.Milliseconds / 10);
    Console.WriteLine("RunTime " + elapsedTime);
}

 

對照組:

實驗組:

 

NYPD無所不在

紐約.時代廣場

 


小結

  • 我們安裝SQL資料庫時,也會希望防毒軟體可以排除.bak .mdf .ndf .ldf或是SQL Bin執行檔所在位置。
  • 最近剛好有兩家客戶討論SQL安裝作業項目,一家銀行說行內有資安不能排除;另一家銀行說,防毒軟體本來就有排,哈! 傷腦筋,後來發現兩家防毒軟體是同一家。

 


參考

Microsoft connect System.IO.File.AppendAllText slow with file containing lines starting with single quote

File.AppendAllText 方法 (String, String)

StreamWriter 類別