一个自动备份软件的实现

目标:一个能按时间间隔,或文件夹发生改变时执行备份的软件。

环境:mfc vs2013

软件界面:


备份按钮是手动执行单次备份,写入配置文件按钮是将参数写入set.ini中,备份目标是一个目录地址,备份源是要备份的目录地址,”;“结束,可多个;

定时备份是按时间间隔备份,时间的单位是ms,开始监视是一旦文件改变立刻备份。

功能分析:

1)备份,其实就是复制操作。

在网上找了一下,复制文件夹可用壳函数SHFileOperation(&sos),sos是结构体SHFILEOPSTRUCT,填上参数后用SHFileOperation(&sos)执行相应操作,具体代码如下:

void Backup(CString src,CString dst){
	Write(_T("back up dir ") + src + _T(" to ") + dst + _T("\r\n"), _T("./Log.txt"), _T("end"));
<span style="white-space:pre">	</span>CreateDirectory(dst,NULL);
	SHFILEOPSTRUCT sos;
	src += _T('\0');
	dst += _T('\0');
	sos.hwnd = NULL;
	sos.pFrom = src;
	sos.pTo = dst;
	sos.wFunc = FO_COPY;
	sos.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
	SHFileOperation(&sos);
	
}

2)读写文件,主要是用来写程序log,读写set.ini,使用cfile读写。

void Write(CString strc, CString addr = _T("./Log.txt"),CString label=_T("begin"),CString label_create=_T("no")){
	int len = strc.GetLength();
	char *log = new char[len];
	WideCharToMultiByte(CP_OEMCP, NULL, strc.GetBuffer(), -1, log, len, NULL, FALSE);
	CFile mFile;
	if (label_create == _T("yes")){ 
		mFile.Open(addr, CFile::modeCreate | CFile::modeReadWrite); 
	}
	else{
		mFile.Open(addr, CFile::modeCreate | CFile::modeReadWrite | CFile::modeNoTruncate);
	}
	
	if (label == _T("end")){
		mFile.SeekToEnd();
	}
	else{
		mFile.SeekToBegin();
	}
	mFile.Write(log, len);
	mFile.Close();
}






CString Read(CString str){
	CFile mFile;
	mFile.Open(str, CFile::modeRead);
	
	int len = mFile.GetLength();
	char *temp = new char[len];
	mFile.Read(temp, len);
	CString strc;
	LPWSTR p = strc.GetBuffer(len);
	MultiByteToWideChar(CP_ACP, 0, temp, -1, p, len);//字符集转换
	strc.ReleaseBuffer();
	
	mFile.Close();
	return strc;
}

3)单次备份的实现:

void CAutoBakcupDlg::OnBnClickedButton1()
{
	SYSTEMTIME st;
	GetLocalTime(&st);
	CString strTime;
	strTime.Format(_T("%4d %2d %2d %2d %2d %2d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
	ReadIni();
	for (int i = 0; i < num; i++){
		Backup(dir_arr[i], dst+_T("\\")+strTime);
	}
	Write(_T("back up dir\r\n"), _T("./Log.txt"), _T("end"));
	//SetDlgItemText(IDC_EDIT2,Read(_T("./Log.txt")));
	CEdit* pedit = (CEdit*)GetDlgItem(IDC_EDIT2);
	pedit->SetSel(-1, -1);
	pedit->ReplaceSel(_T("back up dir\r\n"));
	pedit->LineScroll(pedit->GetLineCount());
}

在这儿,备份到了相应时间为名的文件夹下面


4)定时备份:

在这儿使用了定时器,在mfc中使用定时器还是很简单的,settimer后,添加消息处理程序onTimer,在里面调用上面的备份函数即可。

void CAutoBakcupDlg::OnBnClickedButton3()
{
	// TODO:  在此添加控件通知处理程序代码
	int m = GetDlgItemInt(IDC_EDIT4);
	nIDEvent = CWnd::SetTimer(1,m,NULL);
	Write(_T("timer is on\r\n"), _T("./Log.txt"), _T("end"));
	CEdit* pedit = (CEdit*)GetDlgItem(IDC_EDIT2);
	pedit->SetSel(-1, -1);
	pedit->ReplaceSel(_T("timer is on\r\n"));
	pedit->LineScroll(pedit->GetLineCount());
	
}


void CAutoBakcupDlg::OnBnClickedButton4()
{
	// TODO:  在此添加控件通知处理程序代码
	CWnd::KillTimer(nIDEvent);
	Write(_T("timer is off\r\n"), _T("./Log.txt"), _T("end"));
	CEdit* pedit = (CEdit*)GetDlgItem(IDC_EDIT2);
	pedit->SetSel(-1, -1);
	pedit->ReplaceSel(_T("timer is off\r\n"));
	pedit->LineScroll(pedit->GetLineCount());
}
void CAutoBakcupDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO:  在此添加消息处理程序代码和/或调用默认值
	
	OnBnClickedButton1();
	CDialogEx::OnTimer(nIDEvent);
}

5)检测到文件更改时执行备份。

使用FindFirstChangeNotification系列函数来监控文件夹的更改情况,发现更改就备份。

由于开始监视后,该函数就会一直处于循环状态,如果在mfc中直接调用会导致ui失去响应,因此把这个函数放到子线程中执行。发现文件更改就发送一个消息给主程序。实现如下:

子线程函数

UINT SPY(LPVOID lpParam){
	CString dir=(LPCTSTR)lpParam;
	DWORD dwWaitStatus;
	HANDLE dwChangeHandle;
	dwChangeHandle = FindFirstChangeNotification(
		dir, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
		FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
		);
	if (dwChangeHandle == INVALID_HANDLE_VALUE){
		ExitProcess(GetLastError());
	}


	while (isonspy){
		dwWaitStatus = WaitForSingleObject(dwChangeHandle, -1);
		switch (dwWaitStatus){
		case WAIT_OBJECT_0:
			if (FindNextChangeNotification(dwChangeHandle) == false){
				ExitProcess(GetLastError());
			}
			PostMessage(AfxGetMainWnd()->m_hWnd, WM_SPY, 0, 0);
			break;
		default:
			break;
		}
	}
	return 0;
}

调用子线程:

void CAutoBakcupDlg::OnBnClickedButton5()
{
	// TODO:  在此添加控件通知处理程序代码
	isonspy = true;
	CWinThread ** subthread = new  CWinThread * [num];
	for (int i = 0; i < num; i++){
		subthread[i] = AfxBeginThread(SPY, (LPVOID)(LPCTSTR)dir_arr[i]);
	}
	Write(_T("spy is on\r\n"), _T("./Log.txt"), _T("end"));
	CEdit* pedit = (CEdit*)GetDlgItem(IDC_EDIT2);
	pedit->SetSel(-1, -1);
	pedit->ReplaceSel(_T("spy is on\r\n"));
	pedit->LineScroll(pedit->GetLineCount());
}
响应消息:

afx_msg LRESULT CAutoBakcupDlg::OnSpy(WPARAM wParam, LPARAM lParam)
{
	OnBnClickedButton1();
	return 0;
}


剩下的就是实现细节方面的问题了。

新鲜出炉的效果图:



问题:

界面丑,

如果目标文件夹不存在的话,会出现bug,也就是说要备份到哪,目录需事先建好,(主要是递归建立目录不想写了)

拷贝大文件速度慢,其实backup也应该放到子线程里面

壳函数调试起来太操蛋了,还不如用createdirectory,copyfile自己写一个复制函数

暂时就这样。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值