第八章 文件切割 windows程序设计 王艳平版

///
// MainDir.h文件 // 07MainDir


#include <afxwin.h>
#include <afxcmn.h> // 为了使用CStatusBarCtrl类


#include "FileCutter.h"


class CMyApp : public CWinApp
{
public:
BOOL InitInstance();
};


class CMainDialog : public CDialog
{
public:
CMainDialog(CWnd* pParentWnd = NULL);


protected:
// 进度条控件对象
CProgressCtrl m_Progress;


CFileCutter* m_pCutter;


// 动态控制程序界面的函数
void UIControl();
protected:
virtual BOOL OnInitDialog();
virtual void OnCancel();


afx_msg void OnSourceBrowser();
afx_msg void OnDestBrowser();
afx_msg void OnStart();
afx_msg void OnStop();
afx_msg void OnSelect();
// 处理CFileCutter类发来的消息
afx_msg long OnCutterStart(WPARAM wParam, LPARAM);
afx_msg long OnCutterStatus(WPARAM wParam, LPARAM lParam);
afx_msg long OnCutterStop(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()

};


///
// DirDialog.h文件


#ifndef __DIRDIALOG_H_
#define __DIRDIALOG_H_


#include <shlobj.h>


class CDirDialog
{
public:
CDirDialog();
// 显示对话框
BOOL DoBrowse(HWND hWndParent, LPCTSTR pszTitle = NULL);
// 取得用户选择的目录名称
LPCTSTR GetPath() { return m_szPath; }


protected:
BROWSEINFOA m_bi; 


// 用来接受用户选择目录的缓冲区
char m_szDisplay[MAX_PATH];
char m_szPath[MAX_PATH];
};


CDirDialog::CDirDialog()
{
memset(&m_bi, 0, sizeof(m_bi));


m_bi.hwndOwner = NULL; 
m_bi.pidlRoot = NULL;
m_bi.pszDisplayName = m_szDisplay; 
m_bi.lpszTitle = NULL;
m_bi.ulFlags = BIF_RETURNONLYFSDIRS;

m_szPath[0] = '\0';
}


BOOL CDirDialog::DoBrowse(HWND hWndParent, LPCTSTR pszTitle)
{
if(pszTitle == NULL)
m_bi.lpszTitle = "选择目标文件夹";
else
m_bi.lpszTitle = pszTitle;


m_bi.hwndOwner = hWndParent;
LPITEMIDLIST pItem = ::SHBrowseForFolder(&m_bi);
if(pItem != 0)
{
::SHGetPathFromIDList(pItem, m_szPath);
return TRUE;
}


return FALSE;
}


#endif //__DIRDIALOG_H_



// FileCutter.h文件




#ifndef __FILECUTTER_H_
#define __FILECUTTER_H_


#include <afxwin.h>


// CFileCutter类发给主窗口的通知消息
#define WM_CUTTERSTART WM_USER + 100 // wParam == nTatolCount
#define WM_CUTTERSTOP WM_USER + 101 // wParam == nExitCode, lParam == nCompletedCount
#define WM_CUTTERSTATUS WM_USER + 102 //lParam == nCompletedCount


class CFileCutter
{
public:
// 工作退出代码
enum ExitCode{ 
exitSuccess, // 成功完成任务
exitUserForce,  // 用户终止
exitSourceErr,  // 源文件出错
exitDestErr // 目标文件出错
};


// 构造函数
CFileCutter(HWND hWndNotify);


// 属性
BOOL IsRunning() const { return m_bRunning; }


// 操作
BOOL StartSplit(LPCTSTR lpszDestDir, LPCTSTR lpszSourceFile, UINT uFileSize);
BOOL StartMerge(LPCTSTR lpszDestFile, LPCTSTR lpszSourceDir);


BOOL SuspendCutter();
BOOL ResumeCutter();
void StopCutter();

// 具体实现
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;// Data gard


private:
// 对象的生命周期全局有效的数据
HWND m_hWndNotify;// 接受消息通知事件的窗口句柄
HANDLE m_hWorkEvent;// 通知开始工作的事件对象句柄
CWinThread* m_pThread;// 工作线程
BOOL m_bSuspend;// 暂停标志
BOOL m_bExitThread;// 退出标志
};


#endif // __FILECUTTER_H_



// MainDir.cpp文件


#include <afxdlgs.h> // 为了使用CFileDialog类
#include "DirDialog.h"
#include "resource.h"
#include "Cutter.h"


CMyApp theApp;


BOOL CMyApp::InitInstance()
{
CMainDialog dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
return FALSE;
}


CMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_FILECUTTER_DIALOG, pParentWnd)
{
}


BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
ON_BN_CLICKED(IDC_SOURCEBROWSER, OnSourceBrowser) // 选择源文件的“选择”按钮
ON_BN_CLICKED(IDC_DESTBROWSER, OnDestBrowser) // 选择目标文件的“选择”按钮
ON_BN_CLICKED(IDC_START, OnStart) // 开始“分割”按钮
ON_BN_CLICKED(IDC_STOP, OnStop) // “终止”分割按钮
ON_BN_CLICKED(IDC_SELECTSPLIT, OnSelect) // 分割单选框按钮
ON_BN_CLICKED(IDC_SELECTMERGE, OnSelect) // 合并单选框按钮
// 下面是3各CFileCutter类发来的消息
ON_MESSAGE(WM_CUTTERSTART, OnCutterStart)
ON_MESSAGE(WM_CUTTERSTATUS, OnCutterStatus)
ON_MESSAGE(WM_CUTTERSTOP, OnCutterStop)
END_MESSAGE_MAP()



BOOL CMainDialog::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(theApp.LoadIcon(IDI_MAIN), FALSE);


// 创建CFileCutter对象
m_pCutter = new CFileCutter(m_hWnd);


// 默认选中分割单项框
((CButton*)GetDlgItem(IDC_SELECTSPLIT))->SetCheck(1);
// 初始化单位选择组合框。可以在这里继续添加其它项
((CComboBox*)GetDlgItem(IDC_UNIT))->AddString("1");
((CComboBox*)GetDlgItem(IDC_UNIT))->AddString("30");
((CComboBox*)GetDlgItem(IDC_UNIT))->AddString("60");
((CComboBox*)GetDlgItem(IDC_UNIT))->SetCurSel(0);


// 子类化进度条控件。也就是让m_Progress对象取得进度条控件的控制权
m_Progress.SubclassWindow(*GetDlgItem(IDC_PROGRESS));


UIControl();
return TRUE;
}


void CMainDialog::UIControl()
{
BOOL bIsWorking = m_pCutter->IsRunning();

// 设置选项分组框中3个控件的状态
GetDlgItem(IDC_SELECTSPLIT)->EnableWindow(!bIsWorking);
GetDlgItem(IDC_SELECTMERGE)->EnableWindow(!bIsWorking);
GetDlgItem(IDC_UNIT)->EnableWindow(!bIsWorking);
// 设置分割、终止两个按钮的状态
GetDlgItem(IDC_START)->EnableWindow(!bIsWorking);
GetDlgItem(IDC_STOP)->EnableWindow(bIsWorking);


if(bIsWorking)
{
return;
}

// 根据用户的选择设置不同的文本
BOOL bSplit = ((CButton*)GetDlgItem(IDC_SELECTSPLIT))->GetCheck();
if(bSplit) // 请求分割
{
GetDlgItem(IDC_START)->SetWindowText("分割");
GetDlgItem(IDC_SOURCETITLE)->SetWindowText("请选择要分割的文件:");
GetDlgItem(IDC_DESTTITLE)->SetWindowText("请选择分割后保存到的文件夹:");

GetDlgItem(IDC_UNIT)->EnableWindow(TRUE);
}
else // 请求合并
{
GetDlgItem(IDC_START)->SetWindowText("合并");
GetDlgItem(IDC_SOURCETITLE)->SetWindowText("请选择待合并文件的文件夹:");
GetDlgItem(IDC_DESTTITLE)->SetWindowText("请选择合并后保存到的文件夹:");

GetDlgItem(IDC_UNIT)->EnableWindow(FALSE);
}


// 初始化状态信息
GetDlgItem(IDC_STATUSTEXT)->SetWindowText("    状态显示:");
m_Progress.SetPos(0);


}


void CMainDialog::OnCancel()
{
// 是否真的退出?
BOOL bExit = TRUE;
if(m_pCutter->IsRunning())
{
if(MessageBox("工作还未完成,确实要退出吗?", NULL, MB_YESNO) == IDNO)
{
bExit = FALSE;
}
}


if(bExit)
{
delete m_pCutter;
CDialog::OnCancel();
}
}


void CMainDialog::OnSelect()
{
UIControl();
}


void CMainDialog::OnSourceBrowser()
{
BOOL bSplit = ((CButton*)GetDlgItem(IDC_SELECTSPLIT))->GetCheck();
if(bSplit) // 请求分割
{
CFileDialog sourceFile(TRUE);
// 显示选择文件对话框
if(sourceFile.DoModal() == IDOK)
{
GetDlgItem(IDC_EDITSOURCE)->SetWindowText(sourceFile.GetPathName());

// 设置默认目录
// 例如,如果用户选择文件“D:\cd\精选歌曲.iso”,那么“D:\cd\精选歌曲”将会被设置为默认目录
CString strDef = sourceFile.GetPathName();
strDef = strDef.Left(strDef.ReverseFind('.'));
GetDlgItem(IDC_EDITDEST)->SetWindowText(strDef);
}
}
else // 请求合并
{
CDirDialog sourceFolder;
// 显示选择目录对话框
if(sourceFolder.DoBrowse(*this) == IDOK)
{
GetDlgItem(IDC_EDITSOURCE)->SetWindowText(sourceFolder.GetPath());


// 设置默认目录
// 例如,如果用户选择目录“D:\cd”,那么“D:\cd\cd”将会被设置为默认目录
CString strDef = sourceFolder.GetPath();
strDef.TrimRight('\\');
strDef = strDef + '\\' + strDef.Mid(strDef.ReverseFind('\\') + 1);
// 防止用户选择根目录
strDef.TrimRight(':');
GetDlgItem(IDC_EDITDEST)->SetWindowText(strDef);
}
}
}


void CMainDialog::OnDestBrowser()
{
CDirDialog destFolder;
// 显示选择目录对话框
if(destFolder.DoBrowse(*this) == IDOK)
{
GetDlgItem(IDC_EDITDEST)->SetWindowText(destFolder.GetPath());
}
}


void CMainDialog::OnStart()
{
CString strSource, strDest;


// 检查输入
GetDlgItem(IDC_EDITSOURCE)->GetWindowText(strSource);
GetDlgItem(IDC_EDITDEST)->GetWindowText(strDest);
if(strSource.IsEmpty() || strDest.IsEmpty())
{
MessageBox("文件或路径名称不能为空");
return;
}


BOOL bSplit = ((CButton*)GetDlgItem(IDC_SELECTSPLIT))->GetCheck();
if(bSplit) // 请求分割
{
CString str;
GetDlgItem(IDC_UNIT)->GetWindowText(str);
m_pCutter->StartSplit(strDest, strSource, atoi(str)*1024*1024);
}
else // 请求合并
{
m_pCutter->StartMerge(strDest, strSource);
}
}


void CMainDialog::OnStop()
{
m_pCutter->SuspendCutter();
if(MessageBox("确实要终止吗?", NULL, MB_YESNO) == IDYES)
{
m_pCutter->StopCutter();
}
else
{
m_pCutter->ResumeCutter();
}
}
 

// 下面的代码处理CFileCutter类发来的消息




long CMainDialog::OnCutterStart(WPARAM wParam, LPARAM)// WM_CUTTERSTART 开始工作
{
// 设置进度条范围
int nTotalFiles = wParam;// 总文件数量
m_Progress.SetRange(0, nTotalFiles);

UIControl();
return 0;
}


long CMainDialog::OnCutterStatus(WPARAM wParam, LPARAM lParam)// WM_CUTTERSTATUS 工作进度
{
// 设置进度条进度
int nCompleted = (int)lParam;
m_Progress.SetPos(nCompleted);
// 显示状态
CString s;
s.Format(" 完成%d个文件", nCompleted);
GetDlgItem(IDC_STATUSTEXT)->SetWindowText(s);
return 0;
}


long CMainDialog::OnCutterStop(WPARAM wParam, LPARAM lParam)// WM_CUTTERSTOP 停止工作
{
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;
}



/
// FileCutter.cpp文件


#include "FileCutter.h"




// 内部工作线程
UINT _CutterEntry(LPVOID lpParam)
{
// 得到CFileCutter对象的指针
CFileCutter* pCutter = (CFileCutter*)lpParam;


// 循环处理用户的工作请求
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;
}


//-----------------------接口成员------------------------//


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(); 
}


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);
}


CFileCutter::~CFileCutter()
{
// 设置结束标志
m_bExitThread = TRUE;


// 设置强制退出标志
::EnterCriticalSection(&m_cs);
m_bContinue = FALSE;
::LeaveCriticalSection(&m_cs);


// 防止线程在m_hWorkEvent事件上等待
::SetEvent(m_hWorkEvent);


// 确保工作线程结束
::WaitForSingleObject(m_pThread->m_hThread, INFINITE);

// 释放所有资源
::CloseHandle(m_hWorkEvent);
::DeleteCriticalSection(&m_cs); 
delete m_pThread;
}


BOOL CFileCutter::StartSplit(LPCTSTR lpszDestDir, LPCTSTR lpszSourceFile, UINT uFileSize)
{
if(m_bRunning)
return FALSE;


// 保存参数
::EnterCriticalSection(&m_cs);
m_strSource = lpszSourceFile; 
m_strDest = lpszDestDir;
m_uFileSize = uFileSize;
m_bSplit = TRUE;
::LeaveCriticalSection(&m_cs);


// 通知线程开始工作
::SetEvent(m_hWorkEvent);
return TRUE;
}


BOOL CFileCutter::StartMerge(LPCTSTR lpszDestFile, LPCTSTR lpszSourceDir)
{
if(m_bRunning)
return FALSE;


// 保存参数
::EnterCriticalSection(&m_cs);
m_strSource = lpszSourceDir; 
m_strDest = lpszDestFile;
m_bSplit = FALSE;
::LeaveCriticalSection(&m_cs);


// 通知线程开始工作
::SetEvent(m_hWorkEvent);
return TRUE;
}


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();
}


//-------------------------实现代码-------------------------//




void CFileCutter::DoSplit()
{
int nCompleted = 0;
CString strSourceFile = m_strSource;
CString strDestDir = m_strDest;
CFile sourceFile, destFile;

// 打开源文件
BOOL bOK = sourceFile.Open(strSourceFile,
CFile::modeRead|CFile::shareDenyWrite|CFile::typeBinary);
if(!bOK)
{
// 通知用户,源文件出错
::PostMessage(m_hWndNotify, WM_CUTTERSTOP, exitSourceErr, nCompleted);
return;
}


// 确保目标目录存在(逐层创建它们)
int nPos = -1;
while((nPos = strDestDir.Find('\\', nPos+1)) != -1)
{
::CreateDirectory(strDestDir.Left(nPos), NULL);

::CreateDirectory(strDestDir, NULL);
if(strDestDir.Right(1) != '\\')
strDestDir += '\\';


// 通知用户,开始分割文件
int nTotalFiles = sourceFile.GetLength()/m_uFileSize + 1;
::PostMessage(m_hWndNotify, WM_CUTTERSTART, nTotalFiles, TRUE);

// 开始去读源文件,将数据写入目标文件
const int c_page = 4*1024;
char buff[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::modeWrite|CFile::modeCreate))
{
::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(buff, c_page);
destFile.Write(buff, 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 strSourceDir = m_strSource;
CString strDestFile = m_strDest;
if(strSourceDir.Right(1) != '\\')
strSourceDir += '\\';
if(strDestFile.Right(1) != '\\')
strDestFile += '\\';

// 取得源目录中待合并的文件的文件名称和数量
CString strFileName;
int nTotalFiles = 0;
CFileFind find;
BOOL bRet;
if(find.FindFile(strSourceDir + "*.*"))
{
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 = 0;
while((nPos = strDestFile.Find('\\', nPos+1)) != -1)
{
::CreateDirectory(strDestFile.Left(nPos + 1), NULL);
}
::CreateDirectory(strDestFile, NULL);

// 创建目标文件
CFile sourceFile, destFile;
strDestFile += strFileName;
if(!destFile.Open(strDestFile, CFile::modeRead|CFile::modeWrite|CFile::modeCreate))
{
::PostMessage(m_hWndNotify, WM_CUTTERSTOP, exitDestErr, nCompleted);
return;
}


// 通知用户,开始分割文件
::PostMessage(m_hWndNotify, WM_CUTTERSTART, nTotalFiles, nCompleted);


// 开始去读源文件,将数据写入目标文件
const int c_page = 4*1024;
char buff[c_page];
int nPreCount = 1;
CString sSourceName;
DWORD dwRead;
do
{
// 打开一个源文件
sSourceName.Format("%d__", nPreCount);
sSourceName += strFileName;
if(!sourceFile.Open(strSourceDir + sSourceName, CFile::modeRead|CFile::shareDenyWrite))
{
break;
}


// 将这个源文件中的数据全部写入目标文件
do
{
if(!m_bContinue)
{
sourceFile.Close();
destFile.Close();
if(!m_bExitThread)
::PostMessage(m_hWndNotify, WM_CUTTERSTOP, exitUserForce, nCompleted);
return;
}
dwRead = sourceFile.Read(buff, c_page);
destFile.Write(buff, dwRead);
}
while(dwRead > 0);
sourceFile.Close();


// 通知用户,当前的状态信息
nCompleted = nPreCount++;
::PostMessage(m_hWndNotify, WM_CUTTERSTATUS, 0, nCompleted);
}
while(TRUE);


// 通知用户,工作完成
::PostMessage(m_hWndNotify, WM_CUTTERSTOP, exitSuccess, nCompleted);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值