文件切割系统
通过这个程序的编写,是一个提升,这段代码提现了明显的Windows程序编写的优点,程序的编写我是参考书籍,虽然书籍有部分出错,但是大体的思想还是非常好的。
程序思想
首先我们需要了解文件分割合并工具的一个操作流程,分割文件与合并文件其实就是对文件的一个操作(读取创建写入),我们完全可以通过MFC给我们的CFile类。
程序流程:我们选择分割单选框的时候,我们供用户一个文件打开通用对话框,我们选择合并单选框的时候我们提供用户一个文件夹选择对话框,让给用户选择一个文件夹,然后合并里面的一些固定文件名称的文件(1__文件.*)。
看下程序操作的一些截图:
这个是简单的分割,其实原理不是太难,而且也是有一定的缺陷,但还是一个很典型的Win32程序。
首先我们需要构造我们这个程序的编写思路,首先我们需要我们之前写好的那个CDirDialog类,传送门:https://wker666.github.io/2020/01/19/%E9%80%9A%E7%94%A8%E5%AF%B9%E8%AF%9D%E6%A1%86/
导入这个类之后,但是直接导入到MFC中是不行的,你会发现重定义,需要将我们的那个头文件和源文件分开写。
为了我们后期开发的一个可维护性很高的程序话呢,我感觉适当的“高内聚低耦合”是一个比较重要的一点,所以我们将我们的文件分割操作写到一个类中,正式这个类,完美的提现了Win32编程的巧妙与灵活性。
程序流程
首先我们重要的CFileCutter类是需要提供一个完整的流程,就是从构造函数一被执行我们就需要开启一个线程,这个线程是类中的一个函数,但是类函数是不能作为线程函数的,这个时候就想到了一个很聪明的做法,那就是类的友元函数,虽然函数的格式固定了,但是友元函数的格式不是固定的,开启线程之后,我们设置一个事件对象,这个事件对象是用来控制线程是否继续的,还有有一点很重要就是我们需要一个关键代码段的对象,因为我们可能在多个地方调用成员变量,所以这个东西也是很关键的一点,并且我们使用PostMessage
的方式进行传输我们的消息,这样使我们的接受信息变得不需要有回调函数,程序变得方便了许多。
头文件定义
CFileCutter.h
头文件的定义
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #ifndef __FILECUTTER_H__ #define __FILECUTTER_H__
#define WM_CUTTERSTART WM_USER+100 #define WM_CUTTERSTOP WM_USER+101 #define WM_CUTTERSTATUS WM_USER+102
class CFileCutter { public: enum ExitCode { exitSuccess, exitUserForce, exitSourceErr, exitDestErr }; CFileCutter(HWND hWndNotify); BOOL StartSplit(LPCTSTR lpszDestDir,LPCTSTR lpszSourceFile,UINT nFileSize); BOOL StartMerge(LPCTSTR lpszDestDir,LPCTSTR lpszSourceFile); BOOL SuspendCutter(); BOOL ResumeCutter(); void StopCutter(); BOOL IsRunning(){return m_bRunning;} public: ~CFileCutter();
protected: void Reset(); void DoSplit(); void DoMerge(); UINT friend _CutterEntry(LPVOID lpParam);
CString m_strSource; CString m_strDest; UINT m_uFileSize; BOOL m_bSplit; BOOL m_bContinue; BOOL m_bRunning;
CRITICAL_SECTION m_cs;
private: HWND m_hWndNotify; HANDLE m_hWorkEvent; CWinThread * m_pThread; BOOL m_bSuspend; BOOL m_bExitThread; };
#endif
|
为了防止重定义我们的类,我们需要使用到一些预编译指令。
- 四个参数信息,分别是:源文件,目标文件,是否是分割,每个分割文件的大小
- 两个状态信息:是否继续,是否在运行
- 一个参定值:关键代码段
- 五个受保护的值:窗口句柄(用来接收消息投递的),事件对象,工作线程的一个句柄,是否暂停,是否停止
- 一个枚举类型:包含了当前状态信息(操作成功,用户强行停止,源文件错误,目标文件错误)
- 两个真正的操作函数
- 一个友元线程
- 一个重置状态信息的函数,用来清空我们的一些操作信息。
- 两个间接启动的操作线程
- 三个线程操作函数,分别是暂停,恢复,停止
- 一个检验是不是在运行的函数
看完这些之后,我们对我们的类函数有了一定的了解之后我们就要来编写成员函数了。
类的定义
首先我们需要包含我们的头文件:
1 2
| #include "stdafx.h" #include "CFileCutter.h"
|
stdafx.h
这个头文件是要包含的,因为MFC的东西都在里面。
_CutterEntry
这个使我们的线程函数,里面主要是控制着是否分割合并文件的,控制端就是我们的事件对象。具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| UINT _CutterEntry(LPVOID lParam) { CFileCutter * pCutter = (CFileCutter *)lParam; while(WaitForSingleObject(pCutter->m_hWorkEvent,INFINITE) == WAIT_OBJECT_0 && !pCutter->m_bExitThread) { EnterCriticalSection(&(pCutter->m_cs)); pCutter->m_bRunning = TRUE; LeaveCriticalSection(&(pCutter->m_cs));
if(pCutter->m_bSplit) pCutter->DoSplit(); else pCutter->DoMerge(); pCutter->Reset(); } return 0; }
|
首先我们接受我们传过来的文件切割对象,强制转换一下,然后用WaitForSingleObject
等待我们的事件对象响应,无线等待,并且我们的退出为假。当我们满足了这些要求之后,我们先进入临界区对象,将我们的正在运行设置为真,然后离开(这个真是太仔细了),然后判断是切割还是合并。
然后我们要完成的是构造函数:
1 2 3 4 5 6 7 8 9 10 11 12
| CFileCutter::CFileCutter(HWND hWndNotify) { m_hWndNotify = hWndNotify; m_bExitThread = FALSE; m_bSuspend = FALSE; m_hWorkEvent = CreateEvent(NULL,FALSE,FALSE,NULL); m_pThread = ::AfxBeginThread(_CutterEntry,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL); m_pThread->m_bAutoDelete = FALSE; m_pThread->ResumeThread(); InitializeCriticalSection(&m_cs); Reset(); }
|
这个构造函数是用来初始化我们我们状态信息和启动我们的线程,初始化关键代码段对象的。并且我们需要接受我传递过来的窗口句柄,并重新设置一些信息。
然后我们要看我们的Reset()
这个可能常用,主要是用来刷新我们参数信息的。
1 2 3 4 5 6 7 8 9 10 11 12
| void CFileCutter::Reset() { EnterCriticalSection(&m_cs); m_strSource.Empty(); m_strDest.Empty(); m_uFileSize = 0; m_bSplit = TRUE; m_bContinue = TRUE; m_bRunning = FALSE; LeaveCriticalSection(&m_cs); }
|
重置一些信息,注意还是要进入关键代码段与离开。
在我们的析构函数中,我们需要清空信息,通知活动线程我们结束了,并且删除我们创建的这些对象。
1 2 3 4 5 6 7 8 9 10 11 12 13
| CFileCutter::~CFileCutter() { m_bExitThread = TRUE; EnterCriticalSection(&m_cs); m_bContinue = FALSE; LeaveCriticalSection(&m_cs); SetEvent(m_hWorkEvent); WaitForSingleObject(m_pThread->m_hThread,INFINITE); CloseHandle(m_hWorkEvent); DeleteCriticalSection(&m_cs); delete m_pThread; }
|
首先还是先进入关键代码段,设置我们不运行了,要退出,然后告诉我们的线程函数,别等了,我们要结束了,然后等待线程的完毕,关闭事件对象,删除关键代码段,删除线程。
间接切割合并文件的实现:
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
| BOOL CFileCutter::StartSplit(LPCTSTR lpszDestDir,LPCTSTR lpszSourceFile,UINT nFileSize) { if(m_bRunning) return FALSE; EnterCriticalSection(&m_cs); m_strSource = lpszSourceFile; m_strDest = lpszDestDir; m_uFileSize = nFileSize; m_bSplit = TRUE; LeaveCriticalSection(&m_cs); SetEvent(m_hWorkEvent); return TRUE; } BOOL CFileCutter::StartMerge(LPCTSTR lpszDestDir,LPCTSTR lpszSourceFile) { if(m_bRunning) return FALSE; EnterCriticalSection(&m_cs); m_strSource = lpszSourceFile; m_strDest = lpszDestDir; m_bSplit = FALSE; LeaveCriticalSection(&m_cs); SetEvent(m_hWorkEvent); return TRUE; }
|
这个就是先判断是不是在运行,然后进关键代码段,然后设置一些信息,然后通知线程该工作了。
再接下来就是我们的一些暂停恢复结束操作了:
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
| BOOL CFileCutter::SuspendCutter() { if(m_bRunning) return FALSE; if(!m_bSuspend) { m_pThread->SuspendThread(); m_bSuspend = TRUE; } return TRUE; } BOOL CFileCutter::ResumeCutter() { if(m_bRunning) return FALSE; if(!m_bSuspend) { m_pThread->ResumeThread(); m_bSuspend = FALSE; } return TRUE; } void CFileCutter::StopCutter() { EnterCriticalSection(&m_cs); m_bContinue = FALSE; LeaveCriticalSection(&m_cs); ResumeCutter(); }
|
暂停的话呢先判断是不是在运行,然后调用线程的暂停方法,设置成员变量,恢复也是。停止的话呢就是直接将继续这个变量给结束,然后恢复线程。
下面这个是核心代码:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
| void CFileCutter::DoSplit() { int nCompleted = 0; CString strSourceFile = m_strSource; CString strDestDir = m_strDest; CFile sourceFile,destFile; if (!sourceFile.Open(strSourceFile,CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary)) { PostMessage(m_hWndNotify,WM_CUTTERSTOP,exitSourceErr,nCompleted); return ; } int nPos = -1; while ((nPos = strDestDir.Find("\\",nPos+1)) != -1) { CString str = strDestDir.Left(nPos+1); CreateDirectory(str,NULL); } CreateDirectory(strDestDir,NULL); if(strDestDir.Right(1) != "\\") strDestDir += "\\"; int nTotalFiles = strSourceFile.GetLength()/m_uFileSize+1; PostMessage(m_hWndNotify,WM_CUTTERSTART,nTotalFiles,TRUE);
const int c_page = 4*1024; char Buffer[c_page]; DWORD dwRead; CString sDestName; int nPreCount = 1; UINT uWriteBytes; do { sDestName.Format("%d__",nPreCount); sDestName += sourceFile.GetFileName(); if(!destFile.Open(strDestDir+sDestName,CFile::modeCreate | CFile::modeWrite)) { PostMessage(m_hWndNotify,WM_CUTTERSTOP,exitDestErr,nCompleted); sourceFile.Close(); return; }
uWriteBytes = 0; do { if (!m_bContinue) { destFile.Close(); sourceFile.Close(); if (!m_bExitThread) { PostMessage(m_hWndNotify,WM_CUTTERSTOP,exitUserForce,nCompleted); return; } } dwRead = sourceFile.Read(Buffer,c_page); destFile.Write(Buffer,dwRead); uWriteBytes += dwRead; } while (dwRead > 0 && uWriteBytes <m_uFileSize); destFile.Close();
nCompleted = nPreCount++; PostMessage(m_hWndNotify,WM_CUTTERSTATUS,0,nCompleted); } while (dwRead > 0); sourceFile.Close(); PostMessage(m_hWndNotify,WM_CUTTERSTOP,exitSuccess,nCompleted); }
void CFileCutter::DoMerge() { int nCompleted = 0; CString strSourceFile = m_strSource; CString strDestDir = m_strDest;
if (strSourceFile.Right(1) != "\\") strSourceFile += "\\"; if (strDestDir.Right(1) != "\\") strDestDir += "\\";
CString strFileName; int nTotalFiles = 0; CFileFind find; BOOL bRet; if (find.FindFile(strSourceFile+"*.*")) { do { bRet = find.FindNextFile(); if (find.IsDirectory() && find.IsDots()) continue; if (find.GetFileName().Find("__",0) != -1) { nTotalFiles++; strFileName = find.GetFileName(); } } while (bRet); } find.Close(); if (nTotalFiles == 0) { PostMessage(m_hWndNotify,WM_CUTTERSTOP,exitSourceErr,nCompleted); return; } strFileName = strFileName.Mid(strFileName.Find("__")+2);
int nPos = -1; while ((nPos = strDestDir.Find("\\",nPos+1)) != -1) { CreateDirectory(strDestDir.Left(nPos),NULL); } CreateDirectory(strDestDir,NULL);
CFile sourceFile,destFile; strDestDir += strFileName; if (!destFile.Open(strDestDir,CFile::modeReadWrite | CFile::modeCreate)) { PostMessage(m_hWndNotify,WM_CUTTERSTOP,exitDestErr,nCompleted); return; } PostMessage(m_hWndNotify,WM_CUTTERSTART,nTotalFiles,nCompleted);
const int c_page = 1024*4; char Buffer[c_page]; int nPreCount = 1; CString sSourceName; DWORD dwRead; do { sSourceName.Format("%d__",nPreCount); sSourceName += strFileName; if(!sourceFile.Open(strSourceFile+sSourceName,CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary)) { break; } do { if (!m_bContinue) { sourceFile.Close(); destFile.Close(); if (!m_bExitThread) PostMessage(m_hWndNotify,WM_CUTTERSTOP,exitUserForce,nCompleted); return; } dwRead = sourceFile.Read(Buffer,c_page); destFile.Write(Buffer,dwRead); } while (dwRead > 0); sourceFile.Close(); nCompleted = nPreCount++; PostMessage(m_hWndNotify,WM_CUTTERSTATUS,0,nCompleted); } while (TRUE); destFile.Close(); PostMessage(m_hWndNotify,WM_CUTTERSTOP,exitSuccess,nCompleted); }
|
其实就是操作我们的文件,使用CFile这个类。
分割:先是打开源文件,失败的话呢投递消息,这里要POST而不是Send,然后我们再创建我们的目录,创建完毕目录之后纠正一下目标文件目录。然后我们获取一下文件理论上的道德个数,投递一个开始的消息。然后就是我们简单的初始化呢一下我们的各种信息,进入我们的循环,显示创建目标文件,创建写入的方法打开,出错的话呢就投递消息,然后在判断是不是强行终止了,强行终止的话呢我们就要关一些东西,然后投递我们的消息,然后再读源文件,在写源文件,每次读4KB,这个时候我们要读够用户传递给我们文件大小,关闭文件句柄,发送一个状态消息,一直循环,完毕之后关闭源文件,投递执行成功的消息。
合并:基本和我们的分割一样,显示纠正一下我们的源和目标路径,然后再找一下符合规范的文件,find.IsDirectory() && find.IsDots()
这个其实我感觉有点异议但是没碰见出错。如果一个源文件都没有,肯定要投递错误源文件的错误,在创建目录,投递一下我们要开始了,给他目标文件的大小。再就是初始化变量,进入循环打开源文件,然后判断是不是要继续,然后读写再就是和我们的分割一样了。
类的实际调用
既然我们的类写好了,实际编写的话呢无非就是类的一个调用罢了,首先我们需要配置一下我们的组件,这里就不提了,没啥太大必要,照葫芦画瓢就可以了。
头文件
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
#pragma once #include "CFileCutter.h" #include "CDirDialog.h" #include "afxcmn.h"
class CFileCutterDlg : public CDialogEx {
public: CFileCutterDlg(CWnd* pParent = NULL);
enum { IDD = IDD_FILECUTTER_DIALOG };
protected: virtual void DoDataExchange(CDataExchange* pDX);
protected: HICON m_hIcon; CFileCutter* m_pCutter; CProgressCtrl m_Progress;
virtual BOOL OnInitDialog(); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() void UIControl(void); public: afx_msg void OnBnClickedSelectsplit(); afx_msg void OnBnClickedSelectmergr(); afx_msg void OnBnClickedSourcebrowser(); afx_msg void OnBnClickedDestbrowser(); afx_msg void OnBnClickedStart(); afx_msg void OnBnClickedStop(); afx_msg void OnBnClickedCancel(); protected: afx_msg LRESULT OnCutterstart(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnCutterstop(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnCutterstatus(WPARAM wParam, LPARAM lParam); };
|
就是一个简单的引入,比较关键的就是:
1 2 3
| CFileCutter* m_pCutter; CProgressCtrl m_Progress; void UIControl(void);
|
这三个比较关键,最后一个就是用来调节UI的,其实就是判断你是不是在运行啊,是选了分割还是合并啊之类的。
源文件
CFileCutterDlg::OnInitDialog()
初始化
1 2 3 4 5 6 7 8
| m_pCutter = new CFileCutter(m_hWnd); ((CButton*)GetDlgItem(IDC_SELECTSPLIT))->SetCheck(1); ((CComboBox*)GetDlgItem(IDC_UINT))->AddString("1"); ((CComboBox*)GetDlgItem(IDC_UINT))->AddString("30"); ((CComboBox*)GetDlgItem(IDC_UINT))->AddString("60"); ((CComboBox*)GetDlgItem(IDC_UINT))->SetCurSel(0);
UIControl();
|
这里之前用了子类化控件的一个方法,但我实在没看到用的必要我就给注释,(其实主要是我发现报错,哈哈)
UIControl
函数的实现
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 32
| void CFileCutterDlg::UIControl(void) { BOOL bIsWorking = m_pCutter->IsRunning(); GetDlgItem(IDC_SELECTSPLIT)->EnableWindow(!bIsWorking); GetDlgItem(IDC_SELECTMERGR)->EnableWindow(!bIsWorking); GetDlgItem(IDC_UINT)->EnableWindow(!bIsWorking);
GetDlgItem(IDC_START)->EnableWindow(!bIsWorking); GetDlgItem(IDC_STOP)->EnableWindow(!bIsWorking);
if (bIsWorking) { return; } if (((CButton*)GetDlgItem(IDC_SELECTSPLIT))->GetCheck()) { GetDlgItem(IDC_START)->SetWindowText("分割"); GetDlgItem(IDC_SOURCETITLE)->SetWindowText("请选择要分割的文件:"); GetDlgItem(IDC_DESTTITLE)->SetWindowText("请选择分割后保存到的文件夹"); GetDlgItem(IDC_UINT)->EnableWindow(TRUE); }else { GetDlgItem(IDC_START)->SetWindowText("合并"); GetDlgItem(IDC_SOURCETITLE)->SetWindowText("请选择要合并的文件夹:"); GetDlgItem(IDC_DESTTITLE)->SetWindowText("请选择合并后保存到的文件夹"); GetDlgItem(IDC_UINT)->EnableWindow(FALSE); } GetDlgItem(IDC_STATUSTEXT)->SetWindowText("状态显示"); m_Progress.SetPos(0); }
|
这个的话呢其实也看起来不是很难,就是通过我们的类成员函数判断是不是在运行,是选择的分割还是合并,然后初始化一些控件。
单选框按钮被按下的时候:
1 2 3 4 5 6 7 8 9 10
| void CFileCutterDlg::OnBnClickedSelectsplit() { UIControl(); }
void CFileCutterDlg::OnBnClickedSelectmergr() { UIControl(); }
|
这个就是当按单选框按钮被按下的时候我们进行的操作,就是用来刷新一下我们的一些UI。
当我们点击选择文件夹的时候:
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 32 33 34 35 36 37
| void CFileCutterDlg::OnBnClickedSourcebrowser() { if (((CButton*)GetDlgItem(IDC_SELECTSPLIT))->GetCheck()) { CFileDialog sourceFile(TRUE); if (sourceFile.DoModal() == IDOK) { GetDlgItem(IDC_EDITSOURCE)->SetWindowText(sourceFile.GetPathName()); GetDlgItem(IDC_EDITDEST)->SetWindowText(sourceFile.GetPathName().Left(sourceFile.GetPathName().ReverseFind('.'))); } } else { CDirDialog sourceFolder; if (sourceFolder.DoBrowse(*this) == IDOK) { GetDlgItem(IDC_EDITSOURCE)->SetWindowText(sourceFolder.GetDirPath()); CString strDef = sourceFolder.GetDirPath(); strDef.TrimRight('\\'); strDef = strDef + "\\" + strDef.Mid(strDef.ReverseFind('\\')+1); strDef.TrimRight(":"); GetDlgItem(IDC_EDITDEST)->SetWindowText(strDef); } } }
void CFileCutterDlg::OnBnClickedDestbrowser() { CDirDialog destFolder; if (destFolder.DoBrowse(*this) == IDOK) { GetDlgItem(IDC_EDITDEST)->SetWindowText(destFolder.GetDirPath()); } }
|
这个当我们点击源文件的时候我们就是先判断是风格还是合并,分割的话呢就是文件对话框,合并的话呢就是我们自己写的那个类,不要忘记导入就好了。然后比较聪明的就是:
1 2
| strDef = strDef + "\\" + strDef.Mid(strDef.ReverseFind('\\')+1); strDef.TrimRight(":");
|
这两句,就是生成一个与我们文件夹相同的子文件夹,然后防止了这个根目录(F:\)。
再就是我们点击分割开始的按钮的时候:
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 32 33 34 35 36 37
| void CFileCutterDlg::OnBnClickedStart() { CString strSource,strDest; GetDlgItem(IDC_EDITSOURCE)->GetWindowText(strSource); GetDlgItem(IDC_EDITDEST)->GetWindowText(strDest);
if (strSource.IsEmpty() || strDest.IsEmpty()) { MessageBox("文件或者文件路径不能为空"); return; }
if (((CButton*)GetDlgItem(IDC_SELECTSPLIT))->GetCheck()) { CString str; GetDlgItem(IDC_UINT)->GetWindowText(str); m_pCutter->StartSplit(strDest,strSource,atoi(str)*1024*1024); }else { m_pCutter->StartMerge(strDest,strSource); } }
void CFileCutterDlg::OnBnClickedStop() { m_pCutter->SuspendCutter(); if (MessageBox("确定要终止么?",NULL,MB_YESNO) == IDYES) { m_pCutter->StopCutter(); } else { m_pCutter->ResumeCutter(); } }
|
显示判断是否有填写源文件与目标文件夹,然后判断是分割还是合并,最后调用类的开始方法进行操作。
最后就是我们的消息映射:
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 32 33 34 35 36 37 38 39 40 41 42
| afx_msg LRESULT CFileCutterDlg::OnCutterstart(WPARAM wParam, LPARAM lParam) { int nTotalFiles = wParam; m_Progress.SetRange32(0,nTotalFiles); UIControl(); return 0; }
afx_msg LRESULT CFileCutterDlg::OnCutterstop(WPARAM wParam, LPARAM lParam) { int nErrorCode = wParam; switch(nErrorCode) { case CFileCutter::exitSuccess: MessageBox("操作成功完成","成功"); break; case CFileCutter::exitSourceErr: MessageBox("源文件出错","失败"); break; case CFileCutter::exitDestErr: MessageBox("目标出错","失败"); break; case CFileCutter::exitUserForce: MessageBox("用户终止","失败"); break; } UIControl(); return 0; }
afx_msg LRESULT CFileCutterDlg::OnCutterstatus(WPARAM wParam, LPARAM lParam) { int nCompleted = int (lParam); m_Progress.SetPos(nCompleted); CString s; s.Format("完成%d个文件",nCompleted); GetDlgItem(IDC_STATUSTEXT)->SetWindowText(s); return 0; }
|
效应映射需要我们在类向导中进行声明,不用类向导的话呢要自己写声明和消息映射。
接受到开始的时候,我们需要设置进度条,然后初始化UI,停止的话呢我们要进行停止原因的判断,状态的话呢无非就是完成个数的输出。
程序的不足
- 首先我们是在合并的时候我感觉用for循环更好一些
- 这个要是能用文件映射的话呢应该可以处理更大的文件。