スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

テキストファイルの読み書きクラス

どうもモニターばかり見つめているので目がシバシバしてつらいです。夜になって気になって、目薬を買っておけば良かった・・・orz と二日連続で思っています。

シェル拡張のデバッグ時にログを掃き出すためにテキストファイルを扱うクラスを考えています。ログを掃き出すだけなら書き込みだけで十分ですが、今後のことも考えて読み込みも作ります。私がAPIを直接使いたくない理由としては以下のことがあります。

・CreateFileの引数が多すぎるし、内容も覚えきれないので気軽に使えない。
・行単位の扱いができない。ReadFile、WriteFileの引数も多い。
・エラー時のClose処理の呼び出し忘れを起こしやすい。

例外を使えば、エラー時のClose処理を一元的に行えますが、その場合にはCRTにリンクする必要があります。DLLをあまり大きくしたくないときにはこれが結構効いてきますし、クラスのデストラクタで処理する方が便利です。

というわけけ主に気軽に使えることを目標に設計を考えてみます。


<書き込みと読み込みのクラスを分ける>
自分が今まで1つのファイルに対して同時に読み書きをする必要に迫られたことがないので、これら2つを分けることにします。これによって、読み書きを同時に行うことによる複雑さを回避します。またオープンもシンプルに出来ます。例えば読み込みの場合にファイルを作る必要はありませんので、作成方法に関するフラグは不要になります。

bool Open(CString strFilePath, ShareMode shareMode = NoShare);

今まで文字列引数はLPCTSTRにしてきましたが、今回からATL::CStringにしました。それはマズいというのでしたら誰か止めてください。<(_ _)>
CStringは内部で参照カウンタのようなものを持っていて、CStringのコピーを取るときに内部の文字列を複製するのではなく、ポインタをコピーするという情報をネットで見ました。CStringにもいろいろあるでしょうが、どうなんでしょう?

書き込みのオープンに関しては、

bool Open(CString strFilePath, OpenMode openMode, ShareMode shareMode = NoShare);

のようにOpenModeが余分にあります。ここでCreateNewからAppendを指定します。新規か追加かはより意識するべきだと考え、あえてデフォルト値は設定しないでおきます。

これで読み込みの場合には最低1つ、書き込みの場合には最低2つの引数でオープンできるようになります。また、各引数のパターンも単純です。

<行単位の扱い>
ReadLine、WriteLine関数を用意して文字列を行単位で読み書きできるようにします。私の場合、ScriptingのFileSystemObjectのTextSteamを仕事でよく使うので、あんな感じに近づけます。

<ファイル処理>
CAtlFileをメンバに持ちます。APIを直接使うよりは簡単です。

<エラー処理>
これは結構問題です。ATLのファイル処理はHRESULTを返します。例外も処理できるようですが、その場合もHRESULTをスローします。クラスの各関数が何を返すのか迷いましたが、簡単にするという考え方でboolを返すことにしました。そしてあまり良い方法とは思えませんでしたが、GetLastErrorメンバ関数で最後のHRESULTを取得可能にします。HRESULTをメッセージに変えるためのAPIがFormatMessageですが、私はほとんど使ったことがなく、引数も多くて使いにくいのでここもクラス化しました。コンストラクタでHRESULTを渡すと内部でFormatMessageを呼び出し、デストラクタでバッファを解放します。


こんな感じでできあがればずいぶん処理が楽になりそうです。というか今までもそんなクラスはあったんですけどね。Unicodeビルドに対応してなかったので、今回勉強がてら最初から作り直してます。結構楽しいです。(^^)


ひとつ納得できていないところがあって、キャッシュ処理の有効性についてです。ファイルの読み書きに関してクラス内部でキャッシュしていて、ダイレクトにCAtlFileの関数を毎回呼び出すよりも速いんですが、その分構造が複雑になるのでどの程度速いのかと、単純さを犠牲にするほどの価値があるのかっていうところですかね。10年ほど前に仕事で調べたときには

独自キャッシュ > CRT >> API

って感じで独自キャッシュが圧倒的に早かったんですが、そのころはPentiumの166MHzマシンでしてHDDも今みたいに速くなかったり、OSも9x系だったりしたので、もはや状況が変わってしまっているのかもしれません。もう少し検証して判断しようと思います。
テキストファイルは自分の使い方だとあまり大きなファイルを扱わないんじゃないかと思うので、その辺も微妙です。

といいつつ、今リリースビルドして計ってみたら17MBのテキストファイルの処理で

Write
719ms
2203ms

Read
1063ms
9203ms

という感じでした。数値が小さいのが独自にキャッシュした方です。17MBのテキストファイルはほとんど使わないでしょうけど、Readで9倍の差ってのは大きい気がします。何か別プロセスによる同時アクセスが多くある場合にはより広がる可能性もあるのかもしれませんね。Readは厳密にはReadLineであり、行の読み込みをするためには1文字ずつ改行コードかどうかを調べないといけない点が重要です。キャッシュがない場合、1文字ずつ読みに行くのは何となく嫌な感じはします。いろんなところに別のキャッシュが効いているのかもしれませんが。
もう少し、アルゴリズムも含めてじっくり検証してみようと思います。それができたらいよいよIShellExitInit::Initializeの検証だ~。
関連記事

comment

Secret

カレンダー
04 | 2017/05 | 06
- 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 - - -
カテゴリー
最近の記事
最近のコメント
タグ

カメラ GH2 GH3 

ブログ内検索
月別アーカイブ
RSSフィード
プロフィール
●オンラインソフト作家。しかし長らく活動休止中。
ソフトウェア

●Dさんの長押しIME起動2
●IME+ (仮称)

・Dさんの長押しIME起動。
・Dさんの日本語じゃなきゃイヤン。
・Dさんの名前変更お手伝い。
・Dさんのダイヤルアップ接続お手伝い。
・DさんのWindows終了お手伝い。

・お忍びランチャー。
・お忍びリネーム。
・デジくいっくサーチ!
・Simple Remote
・計算王?

※過去の開発ソフトの一部はリンク先からダウンロードできます。

リンク
FC2カウンター
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。