このところバイナリデータ あーんど C#いじりにハマりつつあるじょにです。
FileStreamクラスを使って、ぐるぐるバイナリ状態でファイルのI/Oをやっていて、体感として
「ファイルの読み込み・書き込みについてだけ考えたら、TextReaderクラスやTextWriterクラスよりもFileStreamを使った方が早いような気がする…」
と思ってちょっと調べてみると、StreamReader/StreamWriterクラスは、byteデータを扱うストリーム・オブジェクトクトをラップしているクラスでした。ああ、やっぱり。(;´Д`)
ということは、「FileStreamを使ってバイナリ状態のままデータを扱った方が、StreamReader/StreamWriterクラスを使うより、処理は早い(≒Text系のストリームでは、I/Oは指定した文字コードでの処理、内部処理はUnicodeのハズ。いちいち文字コードの変換をかけている分、コストがかかっているのではないか?)」──という推論の元に実験開始!
読み込み/書き出しのクラスをセットにして、それぞれ
- StreamReader/StreamWriterクラス
- FileStreamのReadByte/WriteByteメソッド
- FileStreamのRead/Writeメソッド
- System.IO.File.Copyメソッド
で計測してみました。
4.のCopyメソッドについては、当然、バイナリでコピーをやっていると思うので、その際の参考値。予測としては多分一番早い。
コピー元の実験材料は郵便局の郵便番号データをちょちょいと加工して1行を1002バイト(改行キー含むバイト数)、1ファイル全体で117MBくらいになったものです。で、FileStreamのReadクラスやWriteクラスのMaxのバッファは1002にしたので、StreamReader/StreamWriterクラスとI/Oの回数は同一のハズ。メモリの空き容量で差がでてこないように、直前でGC.Colloect();いれてマス。
結果は
- 08.5791859
- 11.1155169
- 05.7603782
- 03.8566569
という具合でした。2.の11秒はさすがに1バイトずつだとI/Oが多くてあまりよい数字はでてこない、ということになりますが。でもまぁI/Oの回数が多いわりには、意外ととStreamReader/StreamWriterクラスに迫っていますよね。最も外付けHDDやネットワーク越しに作業をしたり、ファイルサイズがも巨大であればあるほど、I/Oの問題はもっと顕著になってくるわけですけれどね。
ちなみに実験ソースはこんな感じ。
実験環境はVC#2008Express版(.Net Framework3.5)。
_InFilePath/_OutFilePathは実験クラスのメンバー変数です。
StreamReader/StreamWriterクラスの計測
//------------------------ Stopwatch sw = new Stopwatch(); sw.Reset(); sw.Start(); //------------------------ using (StreamReader _SReder = new StreamReader(_InFilePath, Encoding.GetEncoding(932))) using (StreamWriter _SWriter = new StreamWriter(_OutFilePath, true, Encoding.GetEncoding(932))) { while (_SReder.Peek() != -1) { _SWriter.WriteLine(_SReder.ReadLine()); } } //------------------------ sw.Stop(); MessageBox.Show(sw.Elapsed.ToString()); //------------------------
FileStreamのReadByte/WriteByteメソッドの計測
//------------------------ Stopwatch sw = new Stopwatch(); sw.Reset(); sw.Start(); //------------------------ using (FileStream _FReder = new FileStream(_InFilePath, FileMode.Open, FileAccess.Read)) using (FileStream _FWriter = new FileStream(_OutFilePath, FileMode.Create, FileAccess.Write)) { int _ReadByte = 0; while (_ReadByte != -1) { _ReadByte = _FReder.ReadByte(); _FWriter.WriteByte((byte)_ReadByte); } } //------------------------ sw.Stop(); MessageBox.Show(sw.Elapsed.ToString()); //------------------------
FileStreamのRead/Writeメソッドの計測
//------------------------ int _BufferSize = 1002; //------------------------ Stopwatch sw = new Stopwatch(); sw.Reset(); sw.Start(); //------------------------ using (FileStream _FReder = new FileStream(_InFilePath, FileMode.Open, FileAccess.Read)) using (FileStream _FWriter = new FileStream(_OutFilePath, FileMode.Create, FileAccess.Write)) { byte[] _ReadBuffer = new byte[_BufferSize]; int _ReadSize = _BufferSize; while (_ReadSize != 0) { _ReadSize = _FReder.Read(_ReadBuffer, 0, _BufferSize); _FWriter.Write(_ReadBuffer, 0, _ReadSize); } } //------------------------ sw.Stop(); MessageBox.Show(sw.Elapsed.ToString()); //------------------------
0 件のコメント:
コメントを投稿