このところバイナリデータ あーんど 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 件のコメント:
コメントを投稿