65.9K
CodeProject 正在变化。 阅读更多。
Home

CBFViewCtrl (大文件查看器控件)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (13投票s)

2004年9月8日

4分钟阅读

viewsIcon

77741

downloadIcon

2234

允许您查看非常大的文件的控件。

引言

在像 CEdit/CStatic 这样的控件中查看大文本文件并不容易。特别是当您要查看的文件大小达到数 GB 时(例如非常大的日志文件)。CBFViewCtrl 可以做到这一点。CBFViewCtrl 是一个 CWnd 派生类,可以显示任何大小的文件。该控件只会显示它们,而不会允许您编辑它们。功能

  • 显示任何大小的文件。
  • 能够用鼠标选择文本。
  • 支持标准的“复制到剪贴板”按键(CTRL+C & CTRL+Insert)
  • 将选区复制到剪贴板或文件。
  • 字体/颜色可自定义。
  • 在文件更改时能够自动重新加载。
  • 支持加载拖放到控件上的文件。
  • 设计允许轻松扩展新的视图模式(例如 UTF8、彩色语法文本)。
  • 内存占用低。
  • 高速。

工作原理

它不会将整个文件加载到内存中。它使用内存映射。操作系统允许您将文件映射到内存,但由于没有更多的地址空间了,所以限制约为 2G。而且由于该控件应该能够与其他代码协同工作,因此不应自己占用所有地址空间。所以它一次只映射 256K。并在需要时重新映射到下一个 256K 区域。

CBFViewCtrl 依赖一个派生自 CDataHandler 的辅助类。这些类处理行是如何解析和绘制的。根据选择的视图模式,CBFViewCtrl 加载相应的辅助类。其中包含三个用于不同文本模式的辅助类:ASCII、Unicode 和 Binary。

datahandler 类为最多 400 行保留一个缓存,因此在需要重绘时无需重新解析所有内容。行缓存存储一个指向内存映射区域中行起始位置的指针以及行的字节长度。

由于打开文件时未知总行数,因此垂直滚动条不应设置为文件的行数。而且由于滚动条只允许 32 位值而最大文件大小为 64 位。文件大小也不能用作滚动条的参考。因此,滚动条设置为 10,000。如果用户将滚动条拖到位置 7538,则表示文件进度的 75.38%,它将转到该位置,然后扫描回找到行的开头,并从那里开始显示文件。

限制

在控件中选择所有文本是可能的,即使文件有数 GB 大。如果用户选择将其复制到剪贴板,那将是一个问题。因此,内置了允许的最大剪贴板大小限制(要更改大小限制,请在 BFViewCtrl.h 中更改 MAX_CLIPBOARD_SIZE 的值)。
如果选区大于此值,用户将被要求将其保存到文件中。

使用代码

将控件添加到您的对话框

  1. 在资源编辑器中,向对话框添加一个自定义控件。
  2. 将 ID 设置为“IDC_BFV”之类的名称。
  3. 将类设置为“CBFViewCtrl”。
  4. 将样式设置为 0x50810000。(如果您不想要边框,请将 8 替换为 0)
  5. 在您的对话框类中添加一个成员。
    CBFViewCtrl m_Viewer;
    
  6. 要将对话框中的自定义控件连接到您的类,请在 DoDataExchange 中添加一个 DDX_Control(...)
    void CBFViewCtrlDemoDlg::DoDataExchange(CDataExchange* pDX)
    {
        CDialog::DoDataExchange(pDX);
    
        DDX_Control(pDX, IDC_BFV , m_Viewer );
    }
    
  7. 在控件中打开一个文件。
    m_Viewer.Openfile( strFilename , TEXTTYPE_AUTO , TRUE );
    

要动态创建控件,只需执行此操作。

CRect rc(5,5,400,400);
int nID = 1020;
CBFViewCtrl *pViewer = new CBFViewCtrl();
pViewer->Create( this , rc , nID , WS_VISIBLE | WS_BORDER | WS_CHILD );

配置控件

  • 启用拖放文件支持。
     m_Viewer.DragAcceptFiles( TRUE );
  • 更改颜色。如果颜色为 -1,则该颜色不会改变。
    m_Viewer.SetColor( RGB(255,255,0) , RGB(0,0,0) , 
      RGB(128,0,64) , RGB(255,0,0) , TRUE );
  • 在文件更改时启用自动重新加载。如果 ms 为 0,则检查停止。
    // check for file changes every 2.5s
    m_Viewer.SetReloadChkTimer( 2500 );
  • 更改字体。
    m_Viewer.SetFont( _T("Courier New") , 10 );
    or
    m_Viewer.SetFont( &m_Font );
    
  • 手动设置文本选择。
    // Selection from position 0 to 2300
    m_Viewer.SetSelection( 0 , 2300 );
    

响应来自控件的通知

CBFViewCtrl 在文件打开和文件重新加载时发送通知消息。要对此做出响应,请执行此操作。

  1. 首先添加此项,以便您的对话框类处理消息。
    BEGIN_MESSAGE_MAP(CBFViewCtrlDemoDlg, CDialog)
    
        ON_NOTIFY(  BFVN_OPEN     , IDC_BFV , OnBFVOpen ) 
        ON_NOTIFY(  BFVN_RELOADED , IDC_BFV , OnBFVReloaded ) 
    
    END_MESSAGE_MAP()
    
  2. 然后添加这些函数。
    protected:
        afx_msg void OnBFVOpen (NMHDR *pNotifyStruct, LRESULT* pResult);
        afx_msg void OnBFVReloaded(NMHDR *pNotifyStruct, LRESULT* pResult);
    
  3. 这是它们的使用方式。
    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();
    }
    

待办事项

  • 打印支持
  • 更多视图模式。用于 UTF8、HEX、彩色语法文本的 DataHandlers。

致谢

为了创建这个控件,我使用了一些由其他人创建的类。我想感谢以下几位。

  • Jamie Nordmeyer 贡献的 CAutoFont
  • Richard Chambers 贡献的 文件拖放类
  • Keith Rule 贡献的 MemDC
  • PJ Naughter 贡献的 MemMapFile 类。但我包含的版本已大大修改以满足我的特殊需求,因此我将其重命名为 CMemMapFile2,以避免与原始版本冲突。

历史

  • v1.0 (2004 年 9 月 8 日)
    • First version.
  • v1.1 (2004 年 9 月 9 日)
    • 修复了缓冲区溢出和堆栈溢出问题。
    • 修复了访问内存映射区域之外的内存的问题。
    • 修复了 Unicode 的解析错误。
© . All rights reserved.