お久しぶりです、エンジニアのMasashiです。
前回記事(【C#】ファイル書き込み速度比較)ではtxtファイルの書き込み速度について比較を行いましたが、今回はcsvファイルでは速度差がどうなるのか比較を行いたいと思います。
ファイル形式で書き込み速度に変化が生じるというのは、今までソースコードを書いてきて感じたことはないため特に面白い結果にはならないと思いますが、確認してみたいと思います。
今回もファイルの書き込みを行う関数の速度を4つの方法から検証してみたいと思います。
測定までの流れ
今回測定を行うのは、【0,1,2,3,4,5,6,7,8,9,】という文字列を500,000回、
csv形式で書き込むまでに要した時間になります。
比較対象としてStreamWriterをtry~finallyの形で記載したもの、StreamWriterをusingを使用して記載したもの、AppendAllTextを使用、WriteAllLinesを使用の4つの場合について検証しています。
AppendAllTextについては、毎回ファイルのオープン・クローズが走ることで速度が
どの程度遅くなってしまうのかを計測するために、Loop内で使用するという間違った使い方で計測しています。
測定環境
- CPU:Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz (4 CPUs), ~2.9GHz
- メモリ:16GB
- Visual Studio 2015
対象データ
- 書き込む文字列:0,1,2,3,4,5,6,7,8,9,
- 書き込む回数:500,000
- ファイル形式:csv形式
測定対象
- StreamWriterをtry~finallyで記載
- StreamWriterをusingを使用して記載
- AppendAllTextを使用
- WriteAllLinesを使用
テストコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; namespace FileWriteSpeedTest { class Program { // テストデータ数(書き込み回数) private const int WriteDataCount = 500000; static void Main(string[] args) { var streamWriterTimes = new List<double>(); var usingStreamWriterTimes = new List<double>(); var writeAllTextTimes = new List<double>(); var appendAllTextTimes = new List<double>(); var writeAllLinesTimes = new List<double>(); var arr = MakeArray(); for (var i = 0; i < 10; i++) { streamWriterTimes.Add(StreamWriter()); usingStreamWriterTimes.Add(UsingStreamWriter()); //appendAllTextTimes.Add(AppendAllText()); writeAllLinesTimes.Add(WriteAllLines(arr)); } Console.WriteLine("StreamWriter平均値:" + streamWriterTimes.Average()); Console.WriteLine("UsingStreamWriter平均値:" + usingStreamWriterTimes.Average()); //Console.WriteLine("AppendAllText平均値:" + appendAllTextTimes.Average()); Console.WriteLine("WriteAllLines平均値:" + writeAllLinesTimes.Average()); Console.ReadLine(); } // StreamWriterで書き込み private static double StreamWriter() { var stopwatch = new Stopwatch(); stopwatch.Start(); var sw = new StreamWriter(@"C:\test\test1.csv", true, Encoding.GetEncoding("shift_jis")); try { for(var i = 0; i < WriteDataCount; i++) { sw.Write("0,1,2,3,4,5,6,7,8,9,"); } } finally { sw.Close(); } stopwatch.Stop(); Console.WriteLine("計測時間【StreamWriter】: " + stopwatch.Elapsed.TotalMilliseconds + "ms"); File.Delete(@"C:\test\test1.csv"); return stopwatch.Elapsed.TotalMilliseconds; } // usingを使用したStreamWriterで書き込み private static double UsingStreamWriter() { var stopwatch = new Stopwatch(); stopwatch.Start(); using(var sw = new StreamWriter(@"C:\test\test2.csv", true, Encoding.GetEncoding("shift_jis"))) { for(var i = 0; i < WriteDataCount; i++) { sw.Write("0,1,2,3,4,5,6,7,8,9,"); } } stopwatch.Stop(); Console.WriteLine("計測時間【UsingStreamWriter】: " + stopwatch.Elapsed.TotalMilliseconds + "ms"); File.Delete(@"C:\test\test2.csv"); return stopwatch.Elapsed.TotalMilliseconds; } // AppendAllTextで書き込み // 毎回オープン、クローズ処理が走るので、速度が遅く計測を諦めた // データをまとめて書き込めば何も問題なし //private static double AppendAllText() //{ // var stopwatch = new Stopwatch(); // stopwatch.Start(); // for (var i = 0; i < WriteDataCount; i++) // { // File.AppendAllText(@"C:\test\test3.csv", "0123456789", Encoding.GetEncoding("shift_jis")); // } // stopwatch.Stop(); // Console.WriteLine("計測時間【AppendAllText】: " + stopwatch.Elapsed.TotalMilliseconds + "ms"); // File.Delete(@"C:\test\test3.csv"); // return stopwatch.Elapsed.TotalMilliseconds; //} // WriteAllLinesを使用して書き込み private static double WriteAllLines(string[] arr) { var stopwatch = new Stopwatch(); stopwatch.Start(); File.WriteAllLines(@"C:\test\test4.csv", arr, Encoding.GetEncoding("shift_jis")); stopwatch.Stop(); Console.WriteLine("計測時間【WriteAllLines】: " + stopwatch.Elapsed.TotalMilliseconds + "ms"); File.Delete(@"C:\test\test4.csv"); return stopwatch.Elapsed.TotalMilliseconds; } // テストデータを配列形式で作成 private static string[] MakeArray() { var r = new Random(); var arr = new string[WriteDataCount]; for (var i = 0; i < WriteDataCount; i++) { arr[i] = "0,1,2,3,4,5,6,7,8,9,"; } return arr; } } } |
ファイル書き込み速度の測定結果
10回試行した結果の平均値が下記になっています。小数点第1位で四捨五入しています。
計測項目 | 計測時間(ms) |
---|---|
StreamWriterをtry~finallyで記載 | 127 |
StreamWriterをusingを使用して記載 | 120 |
AppendAllTextを使用 | 測定不能 |
WriteAllLinesを使用 | 164 |
結果の比較の前にAppendAllTextを使用したパターンですが前回同様、毎回ファイルのオープン・クローズを行うため、結果の取得に非常に時間がかかり、計測することを諦めたため、計測不能という形で記載させていただきました。
結果も前回同様非常に似通っており、StreamWriterを使用したパターンよりusingを使用したほうが若干ですが早くなっています。
また、前回よりも全体的に速度が遅い状態で結果は出ていますが、純粋に「,」が文字として増えているため、その分の時間が計測結果の時間に現れたと考えられます。
ファイル書き込み速度のまとめ
結論につきましては、前回と同様になってしまいますが、再度載せさせていただきます。
AppendAllTextを使用する場合は、データを加工してから使用することで、ファイルのオープン・クローズ処理を意識する必要がないため非常に便利です。
StreamWriterを使用する場合は、非常に小さい値ですが速度差が生まれるため、usingを使用して実装するのがいいかと思います。
またusingを使用することでClose処理を意識しなくてすむため、finallyでClose処理を入れることを忘れていたようなバグを防ぐことができます。
WriteAllLinesを使用する場合は、改行を入れる処理を意識しなくていいため、取得したデータを改行して書き込んでほしいという要望がある場合は使用することになると思います。
今回の計測によりファイルの違いでは、速度差を見つけることができませんでした。よってファイルの拡張子が異なっていたとしても状況に応じて使用する関数を変更して問題ないと考えられます。
この記事が少しでも皆さんのお役に立てば幸いです。