.NET 4 BCL の新機能 (2) : ファイル IO の改善
.NET 4 では System.IO の読み込み系 API が改善され、遅延ロード用メソッドが追加されるらしい。
例えば File クラス。ReadAllLines というメソッドがあるが、メソッドを呼び出した時点でファイル内の全データをバッファリングするので、巨大なファイルを読み込むと return まで結構待たされることになる。この問題を解決するために、同様の処理を行う ReadLines メソッドが追加された。ReadLines は IEnumerable<string> を返すが、呼び出した時点ではデータを読み込まず、foreach などでデータを使おうとした際に初めてデータの読み込みを行う。
試しに 50 万行のテキストファイルを読み込んで、List<string> に各行を Add するプログラムを作って、ReadAllLines と ReadLines の処理時間を比較した。return が早い分、処理時間に多少コストがかかるかもと思いきや、全然そんなことはないようだ。
ReadAllLines | ReadLines | |
return までの時間 | 0.4 から 0.47 秒 | 0.02 から 0.1 秒 |
全行バッファリングまでの時間 | 0.67 から 0.74 秒 | 0.36 から 0.73 秒 |
DirectoryInfo クラスにも EnumerateFiles というメソッドが追加された。これも ReadLines と同じく IEnumerable<FileInfo> だけ return しておき、データを使う時に初めてファイルシステムからファイルの情報を取得する。
LINQ と一緒に使うと特に効果的だ。下のコードは MSDN マガジンに載っているもので、C:\logs フォルダにある拡張子 log のファイルから、Error: で始まる行だけを抜き出す処理。新 API を使うと、フォルダの全ファイルを取得する必要も、ファイルの全行を読み込んでくる必要もなく、条件にあったファイル、行だけが errorlines コレクションに追加されることになる。
var errorlines =
from file in Directory.EnumerateFiles(@"C:\logs", "*.log")
from line in File.ReadLines(file)
where line.StartsWith("Error:", StringComparison.OrdinalIgnoreCase)
select string.Format("File={0}, Line={1}", file, line);
File.WriteAllLines(@"C:\errorlines.log", errorlines);
Comments
Post a Comment