Mesoscopic Programming

タコさんプログラミング専門

ファイルビュワー作成日誌 #006:テキストビュワー

概要

テキストビュワーができました。

但し、開くときの文字コードチェックが遅いのであとで改良します。
一度開いてしまえば、表示は速いですから。
1文字でも表示できない文字が入ってたらエラーではじいてるんですが、
ファイルサイズがでかいやつは、先頭の何行かに絞った方がビュワーとしては合目的的かと思いやす。
現状、ファイルサイズが 100KB 超えるといらつくレベルです。
文字コードは Shift-JIS 以外に UnicodeUTF-8 に対応しました。
Unicode は BOM 必須ですが、UTF-8 はあってもなくても構いません。
開くとき全部スキャンしてるんで。


実行画面と実行ファイル

  1. FileView.zip


テキストビュークラス

テキストビュークラスは、ファイルビュークラスの派生クラスです。
Open() 関数でファイルオープンするとき、CheckFileType() 関数でテキストファイルかどうかチェックしてます。
なのでファイル拡張子とか一切無視してチェックします。
そのファイルに表示可能なデータしかなければ、それはテキストファイルとみなします。
なのでXファイルとか各種ソースファイルとか、拡張子をチェックする必要が一切ありません。
手抜きするためならどんな苦労も厭いません。
その代わり、でかいテキストファイルを開くのが遅いです。
本当のバイナリファイルならすぐチェックではじかれるので問題ないのですが、
Xファイルのソースみたいな、メガサイズのテキストファイルはちょっと非実用レベルです。

class TextView : public FileView
{
public :

    struct LinePos
    {
        UINT     line;
        LONGLONG pos;
    };

    static const INT     nMaxLinePos   = 1000;
    static const INT     nMinLineBound = 100;
    static const LPCTSTR pszKeyTabSize;

public :

    LinePos linePos[ nMaxLinePos ];
    UINT    nLinePosCount;
    UINT    nLinePosBound;
    UINT    nTabSize;
    BOOL    bEOF;
    BOOL    bError;
    UINT    nLineColumn;

public :

    virtual inline LPCTSTR GetRegistClassName() { return _T( "ClassTextView" ); }
    virtual inline LPCTSTR GetSectionName()     { return _T( "TextView" ); }
    virtual BOOL           CheckFileType();
    virtual BOOL           ScanLineToFileEnd( UINT line );
    virtual VOID           UpdateFileData( LONGLONG pos, LONGLONG size );
    virtual VOID           AddLinePos( UINT line, LONGLONG pos );
    virtual LONGLONG       GetLinePos( UINT line );
    virtual DWORD          ScanLineData( LPTSTR buffer = NULL, DWORD size = 0, TCHAR chTab = _T( ' ' ) );
    virtual LRESULT        OnWmCreate();
    virtual LRESULT        OnWmDestroy();
    virtual LRESULT        OnWmPaint();
};
解説

linPos 配列には、適当な間隔で行のファイルポジションが保存されてます。
なので表示の時は速いのです。
以前エディットコントロールをファイルビュワーとして使おうとしましたが、とてもとても遅くて使い物になりませんでした。
なので表示だけは速いものにしたかったのです。
オープンするときファイルビュークラスの方でコードページをチェックしてますが、
BOM なしの UTF-8 に関しては、こっちの ScanLineData() 関数でチェックしてます。
ScanLineData() 関数では、スキャンするついでに表示文字列も作成します。