Introduction
View large text file in a controller like
CEdit
/CStatic
is not easy. Especially if the file you
want to view is several gigabytes big (like very big log files).
CBFViewCtrl
can do this. CBFViewCtrl
is a
CWnd
-Derived class that will show files of any size. The controller
will only show them. Will not allow you to edit them. Features:
- Show files of any size.
- Able to select text with mouse.
- Support for standard 'copy to Clipboard' keys ( CTRL+C & CTRL+Insert )
- Copy Selection to Clipboard or File.
- Font / Color are customizable.
- Able to auto reload if file is changed.
- Support for loading file that are dropped on the controller.
- Design that allow for easy expansions of new view modes. (e.g. UTF8 , Color
Syntax text )
- Low memory usage.
- High Speed.
How it works
It doesn�t load the entire file into memory. It is using memory mapping. The
OS allows you to map a file to memory but the limit is around 2G since then
there is no more address space left. And since this controller should be able to
work together with other code it should not take all of the address space for it
self. So it is only mapping 256K at one time. And it will remap to the next 256K
area when needed.
CBFViewCtrl
depends on a helper class
that is derived from CDataHandler
. This classes handle how lines
for parsed and drawn. Depending on what view mode is chosen
CBFViewCtrl
load appropriate helper. There are three helpers
includes for different Text Modes , ASCII , Unicode and Binary.
The
datahandler class keeps a cache for up to 400 lines so it doesn�t need to
reparse everything when we need to redraw. The line cache store a pointer to
where in the memory mapped area the line starts and how long the line is in
bytes.
Since the total number of rows is unknown when opening a file the
vertical scrollbar should not be set to the numbers of lines the file has. And
since the scrollbar only allows 32bit values and max file size is 64bit. The
file size could not be used as a reference either for the scrollbar. So instead
the scroll bar is set to 10.000. And if user drag scrollbar to position 7538
this is translated to 75.38% into the file and it will go there and then scan
backward to file the beginning of the line and start showing the file from
there.
Limits
It is possible to select ALL text in the controller even if the file is
several gigabytes big. And if the user then should choose to copy that to the
clipboard it will be a problem. So there is a build in limit of the max size of
the allowed clipboard size ( For another size limit change the value of
MAX_CLIPBOARD_SIZE
in BFViewCtrl.h ).
If the selection is bigger
then this value the user will be asked to save the clip to a file instead.
Using the code
To add the controller to you Dialog:
- In the resource editor add a custom control to the dialog.
- Set ID to something like "IDC_BFV".
- Set class to "CBFViewCtrl.
- Set Style to 0x50810000. (Replace the 8 with 0 if you do not want any
border)
- Add a member to you Dialog class.
CBFViewCtrl m_Viewer;
- To connect the custom controler in the dialog to your class add a
DDX_Control(...)
to DoDataExchange
. void CBFViewCtrlDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BFV , m_Viewer );
}
- Open a file in the controller.
m_Viewer.Openfile( strFilename , TEXTTYPE_AUTO , TRUE );
To Create the controller dynamically you only have to do this.
CRect rc(5,5,400,400);
int nID = 1020;
CBFViewCtrl *pViewer = new CBFViewCtrl();
pViewer->Create( this , rc , nID , WS_VISIBLE | WS_BORDER | WS_CHILD );
Configure the controller
- Enable drop file support.
m_Viewer.DragAcceptFiles( TRUE );
- Change Colors. If a color is -1 that color will not change.
m_Viewer.SetColor( RGB(255,255,0) , RGB(0,0,0) ,
RGB(128,0,64) , RGB(255,0,0) , TRUE );
- Enable auto reload if file changes. If ms are 0 then the checking is
stopped.
m_Viewer.SetReloadChkTimer( 2500 );
- Change Font.
m_Viewer.SetFont( _T("Courier New") , 10 );
or
m_Viewer.SetFont( &m_Font );
- Set text selection manually.
m_Viewer.SetSelection( 0 , 2300 );
React on notification from the controller
CBFViewCtrl
send a notification message when a file is opened
and when file is reloaded. To react on them do this.
- First add this to let you dialog class handle the messages.
BEGIN_MESSAGE_MAP(CBFViewCtrlDemoDlg, CDialog)
ON_NOTIFY( BFVN_OPEN , IDC_BFV , OnBFVOpen )
ON_NOTIFY( BFVN_RELOADED , IDC_BFV , OnBFVReloaded )
END_MESSAGE_MAP()
- The Add this functions.
protected:
afx_msg void OnBFVOpen (NMHDR *pNotifyStruct, LRESULT* pResult);
afx_msg void OnBFVReloaded(NMHDR *pNotifyStruct, LRESULT* pResult);
- Here is how they can be used.
void CBFViewCtrlDemoDlg::OnBFVOpen(NMHDR *pNotifyStruct, LRESULT* pResult)
{
m_strFilename = m_Viewer.GetFileName();
}
void CBFViewCtrlDemoDlg::OnBFVReloaded(NMHDR *pNotifyStruct, LRESULT* pResult)
{
m_nFilesize = m_Viewer.GetTotalSize();
}
To Do
- Print Support
- More view modes. DataHandlers for UTF8 , HEX , Color Syntax Text
Credits
To create this controller I have used some classes create by other people. I
would like to thanks the following guys.
- Jamie Nordmeyer for CAutoFont
- Richard Chambers for File Drag & Drop
class
- Keith Rule for MemDC
- PJ Naughter for MemMapFile class. But
the version included here is highly modified to fit my special needs, so I
renamed it to
CMemMapFile2
so it would not conflict with the
original version.
History
- v1.0 ( 8-September-2004 )
- v1.1 ( 9-September-2004 )
- Buffer overflow and stack overflow problem fixed.
- Accessing memory out of memory mapped area problem fixed.
- Parse bug for Unicode fixed.