CBFViewCtrl (BigFile Viewer Controller)






4.79/5 (13 votes)
Sep 8, 2004
4 min read

76786

2234
Controller that allows you to view very large files
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(...)
toDoDataExchange
.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.
// check for file changes every 2.5s m_Viewer.SetReloadChkTimer( 2500 );
- Change Font.
m_Viewer.SetFont( _T("Courier New") , 10 ); or m_Viewer.SetFont( &m_Font );
- Set text selection manually.
// Selection from position 0 to 2300 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) { // A file was open. m_strFilename = m_Viewer.GetFileName(); } void CBFViewCtrlDemoDlg::OnBFVReloaded(NMHDR *pNotifyStruct, LRESULT* pResult) { // File is reload. the filesize have change. get the new size 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 )
- First version.
- 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.