两种开发方式
- 瀑布式开发
有需求 -> 分析 -> 建模 -> 编码 -> 维护 所有的类全部是自己设计编码的 - 敏捷开发
需求 -> 编码 -> 重构(建模) -> 编码 需求总是变化的 -> 代码也需要变化
所谓的敏捷开发就是拿着开源项目修改为自己的项目,随着时间的推移,改变的越来越多的内容,最后可能将原来开源项目中的所有内容都改为自己的内容。
当前类的性质,
类方法及类成员设计的时候
1. 方法及成员的时间和空间取舍
2. 类和类之间除了继承等之外,没有任何关系,每个类只负责把本类的业务逻辑处理好就可以了。
针对这些问题,将原来的文件分割少做了一些改进,其中包括CMyPartFile类的逻辑改进以及多线程的使用,多线程使得在处理大文件的时候,不会让界面卡死。
下面是代码,直接直接贴上去了:
//MySplitAndMerge.h文件
#pragma once
#include <vector>
class CMyPartFile : public CFile
{
public:
enum eModal
{
MODAL_SPLIT,
MODAL_MERGE
};
private:
typedef struct tagPartFileNameHeader
{
WORD wFlag;
WCHAR wstrFirstFileName[MAX_PATH];
WCHAR wstrNextFileName[MAX_PATH];
UINT uOriginalFileSize;
} PARTFILENAMEHEADER;
public:
// 构造的时候只是负责打开或者创建一个文件,这个需要根据模式来定
// 算了,还是不在构造函数中进行打开或者创建了,在构造函数中只做参数的配置
// 如果是分割,那么就在保存的时候进行打开,写入
// 如果是合并,就在获取数据的时候进行打开,读取
CMyPartFile(const CString strFilePath, eModal modal);
~CMyPartFile();
BOOL IsValidPartFile(BOOL bNeedClose);
WCHAR *GetFirstFileName();
WCHAR *GetNextFileName();
UINT GetOriginalFileSize() const;
BOOL SaveDataToFile(WORD wFlag, CString strFirstFileName, CString strNextFileName, UINT uOriginalFileSize, const BYTE *pByte);
UINT GetDataFromFile(BYTE *pByte);
private:
void CheckPartFileHeader(); // 这个函数有待于验证是否有必要存在
BOOL MyOpenFile();
private:
PARTFILENAMEHEADER m_partFileNameHeader;
CString m_strFilePath;
eModal m_modal;
BOOL m_bInitPartFileHeader;
};
// 专门操作CMyPartFile类的类
class CMySplitAndMerge
{
public:
/**
* \brief
* \param strFolderName 待分割文件所在的文件夹名字
* \param strFileName 待分割文件的名字
* \param bSplitByFileSize 分割的类型:
* \param uNumber
* \return
*/
BOOL Split(const CString strFolderName, const CString strFileName, BOOL bSplitByFileSize, UINT uNumber);
BOOL Merge(const CString strFolderName, const CString strFileName, const CString strDestFileName);
private:
BOOL MyOpenFile(CFile& file, const CString strFilePath, BOOL bRead) const;
CString CreateDir(const CString strFileName);
/**
* \brief 根据分割文件的个数计算出分割文件的大小
* \param strFilePath 待分割文件路径
* \param uNumber 待分割文件个数
* \return 如果返货0,表示计算失败,否则返回每个分割文件的大小
*/
UINT CalcFileSize(const CString strFilePath, UINT uFileNumber) const;
BOOL SplitFileByFileSize(const CString strFolderName, const CString strFilePath, UINT uFileSize) const;
BOOL GetAllPartFile(const CString strFolderName, const CString strFileName);
private:
std::vector<CMyPartFile *> m_vecMyPartFile;
};
#include "stdafx.h"
#include "MySplitAndMerge.h"
//MySplitAndMerge.cpp文件
CMyPartFile::CMyPartFile(const CString strFilePath, eModal modal) : CFile(), m_strFilePath(strFilePath), m_modal(modal), m_bInitPartFileHeader(FALSE)
{
}
CMyPartFile::~CMyPartFile()
{
}
BOOL CMyPartFile::IsValidPartFile(BOOL bNeedClose)
{
CheckPartFileHeader();
if (bNeedClose)
{
Close();
}
return m_partFileNameHeader.wFlag == MAKEWORD('P', 'o');
}
WCHAR* CMyPartFile::GetFirstFileName()
{
return m_partFileNameHeader.wstrFirstFileName;
}
WCHAR* CMyPartFile::GetNextFileName()
{
return m_partFileNameHeader.wstrNextFileName;
}
UINT CMyPartFile::GetOriginalFileSize() const
{
return m_partFileNameHeader.uOriginalFileSize;
}
BOOL CMyPartFile::SaveDataToFile(WORD wFlag, CString strFirstFileName, CString strNextFileName, UINT uOriginalFileSize, const BYTE *pByte)
{
m_partFileNameHeader.wFlag = wFlag;
wcscpy_s(m_partFileNameHeader.wstrFirstFileName, strFirstFileName);
wcscpy_s(m_partFileNameHeader.wstrNextFileName, strNextFileName);
m_partFileNameHeader.uOriginalFileSize = uOriginalFileSize;
BOOL bRet = TRUE;
if (MyOpenFile())
{
Write(&m_partFileNameHeader, sizeof(PARTFILENAMEHEADER));
Write(pByte, uOriginalFileSize);
Close();
}
else
{
bRet = FALSE;
}
return bRet;
}
UINT CMyPartFile::GetDataFromFile(BYTE* pByte)
{
UINT uReadByte = 0;
if (m_partFileNameHeader.uOriginalFileSize == Read(pByte, m_partFileNameHeader.uOriginalFileSize))
{
uReadByte = m_partFileNameHeader.uOriginalFileSize;
}
Close();
return uReadByte;
}
void CMyPartFile::CheckPartFileHeader()
{
if (!m_bInitPartFileHeader)
{
MyOpenFile();
if (Read(&m_partFileNameHeader, sizeof(PARTFILENAMEHEADER)) == sizeof(PARTFILENAMEHEADER))
{
m_bInitPartFileHeader = TRUE;
}
}
}
BOOL CMyPartFile::MyOpenFile()
{
BOOL bRet = FALSE;
WCHAR strErrorMessage[MAXBYTE] = { 0 };
CFileException fileException;
UINT nOpenFlags = CFile::typeBinary;
if (MODAL_SPLIT == m_modal)
{
nOpenFlags |= (CFile::modeCreate | CFile::modeWrite);
}
else
{
nOpenFlags |= CFile::modeRead;
}
if (Open(m_strFilePath, nOpenFlags, &fileException))
{
bRet = TRUE;
}
else
{
fileException.GetErrorMessage(strErrorMessage, MAXBYTE);
AfxMessageBox(strErrorMessage);
}
return bRet;
}
BOOL CMySplitAndMerge::Split(const CString strFolderName, const CString strFileName, BOOL bSplitByFileSize, UINT uNumber)
{
BOOL bRet = FALSE;
UINT uFileSize = uNumber;
if (!bSplitByFileSize)
{
uFileSize = CalcFileSize(strFolderName + L"\\" + strFileName, uNumber);
}
if (uFileSize > 0)
{
// 开始分割文件
CString strDirName;
strDirName = CreateDir(strFileName);
CreateDirectory(strFolderName + L"\\" + strDirName, nullptr);
bRet = SplitFileByFileSize(strFolderName + L"\\" + strDirName, strFolderName + L"\\" + strFileName, uFileSize);
}
else
{
AfxMessageBox(TEXT("分割的文件大小不能为0"));
}
return bRet;
}
BOOL CMySplitAndMerge::Merge(const CString strFolderName, const CString strFileName, const CString strDestFileName)
{
BOOL bRet = TRUE;
if (GetAllPartFile(strFolderName, strFileName))
{
CFile file;
if (MyOpenFile(file, strFolderName + L"\\" + strDestFileName, FALSE))
{
for (auto value : m_vecMyPartFile)
{
UINT uOriginalFileSize = value->GetOriginalFileSize();
BYTE *pByte = new BYTE[uOriginalFileSize];
memset(pByte, 0, uOriginalFileSize);
UINT uReadFileLength = value->GetDataFromFile(pByte);
if (uReadFileLength != uOriginalFileSize)
{
bRet = FALSE;
break;
}
file.Write(pByte, uReadFileLength);
}
file.Close();
m_vecMyPartFile.clear();
}
}
return bRet;
}
BOOL CMySplitAndMerge::MyOpenFile(CFile& file, const CString strFilePath, BOOL bRead) const
{
CFileException fileException;
UINT nOpenFlags = CFile::typeBinary;
if (bRead)
{
nOpenFlags |= CFile::modeRead;
}
else
{
nOpenFlags |= (CFile::modeCreate | CFile::modeWrite);
}
BOOL bRet = file.Open(strFilePath, nOpenFlags, &fileException);
if (!bRet)
{
WCHAR strErrorMessage[MAXBYTE] = { 0 };
fileException.GetErrorMessage(strErrorMessage, MAXBYTE);
bRet = FALSE;
AfxMessageBox(strErrorMessage);
}
return bRet;
}
CString CMySplitAndMerge::CreateDir(const CString strFileName)
{
CString strDirName;
for (int i = 0; i < strFileName.GetLength(); ++i)
{
if (strFileName.GetAt(i) != L'.')
{
strDirName += strFileName.GetAt(i);
}
else
{
break;
}
}
return strDirName;
}
UINT CMySplitAndMerge::CalcFileSize(const CString strFilePath, UINT uFileNumber) const
{
UINT uRet = 0;
CFile file;
if (MyOpenFile(file, strFilePath, TRUE))
{
uRet = static_cast<UINT>(file.GetLength() % uFileNumber ? file.GetLength() / uFileNumber + 1 : file.GetLength() / uFileNumber);
}
return uRet;
}
BOOL CMySplitAndMerge::SplitFileByFileSize(const CString strFolderName, const CString strFilePath, UINT uFileSize) const
{
BOOL bRet = FALSE;
BYTE *pByte = new BYTE[uFileSize];
memset(pByte, 0, uFileSize);
CFile file;
if (MyOpenFile(file, strFilePath, TRUE))
{
ULONGLONG ullFileLength = file.GetLength();
ULONGLONG ullReadLength = 0;
UINT uReadByteNumber, uPartFileCount = 0;
CString strFirstFileName = TEXT("0.part"), strCurFileName, strNextFileName;
while (true)
{
uReadByteNumber = file.Read(pByte, uFileSize);
ullReadLength += uReadByteNumber;
strCurFileName.Format(L"%s\\%d.part", strFolderName.GetString(), uPartFileCount++);
strNextFileName.Format(L"%d.part", uPartFileCount);
if (ullReadLength >= ullFileLength)
{
strNextFileName = L"NULL";
bRet = TRUE;
}
CMyPartFile myPartFile(strCurFileName, CMyPartFile::MODAL_SPLIT);
myPartFile.SaveDataToFile(MAKEWORD('P', 'o'), strFirstFileName, strNextFileName, uReadByteNumber, pByte);
if (bRet)
{
break;
}
memset(pByte, 0, uFileSize);
}
}
return bRet;
}
BOOL CMySplitAndMerge::GetAllPartFile(const CString strFolderName, const CString strFileName)
{
BOOL bRet = FALSE;
CMyPartFile myPartFile(strFolderName + L"\\" + strFileName, CMyPartFile::MODAL_MERGE);
if (myPartFile.IsValidPartFile(TRUE))
{
CString strCurFilePath, strNextFilePath = myPartFile.GetFirstFileName();
while (true)
{
strCurFilePath = strFolderName + L"\\" + strNextFilePath;
CMyPartFile *pFile = new CMyPartFile(strCurFilePath, CMyPartFile::MODAL_MERGE);
if (pFile->IsValidPartFile(FALSE))
{
m_vecMyPartFile.push_back(pFile);
strNextFilePath = pFile->GetNextFileName();
if (strNextFilePath == L"NULL")
{
bRet = TRUE;
break;
}
strCurFilePath = strFolderName + L"\\" + strNextFilePath;
}
else
{
break;
}
}
}
return bRet;
}
// FileSplitAndMergeDlg.h : 头文件
//
#pragma once
#define WM_MYINFO (WM_USER + 100)
class CMySplitAndMerge;
// CFileSplitAndMergeDlg 对话框
class CFileSplitAndMergeDlg : public CDialogEx
{
// 构造
public:
CFileSplitAndMergeDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_FILESPLITANDMERGE_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CMySplitAndMerge *m_pMySplitAndMergeFile;
afx_msg void OnBnClickedButtonSplit();
afx_msg void OnBnClickedButtonMerge();
afx_msg LRESULT OnMyInfo(WPARAM wParam, LPARAM lParam);
static UINT ThreadFunc(LPVOID pParm);//线程函数的定义
CString m_strFolderName;
CString m_strFileName;
CString m_strDestFileName;
UINT m_uFileSize;
BOOL m_bSplitByFileSize;
BOOL m_bSplit;
CWinThread *m_pThread;
};
// FileSplitAndMergeDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "FileSplitAndMerge.h"
#include "FileSplitAndMergeDlg.h"
#include "afxdialogex.h"
#include "MySplitAndMerge.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CFileSplitAndMergeDlg 对话框
CFileSplitAndMergeDlg::CFileSplitAndMergeDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_FILESPLITANDMERGE_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CFileSplitAndMergeDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CFileSplitAndMergeDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_SPLIT, &CFileSplitAndMergeDlg::OnBnClickedButtonSplit)
ON_BN_CLICKED(IDC_BUTTON_MERGE, &CFileSplitAndMergeDlg::OnBnClickedButtonMerge)
ON_MESSAGE(WM_MYINFO, &CFileSplitAndMergeDlg::OnMyInfo)
END_MESSAGE_MAP()
// CFileSplitAndMergeDlg 消息处理程序
BOOL CFileSplitAndMergeDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
m_pMySplitAndMergeFile = new CMySplitAndMerge();
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
void CFileSplitAndMergeDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。
void CFileSplitAndMergeDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CFileSplitAndMergeDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CFileSplitAndMergeDlg::OnBnClickedButtonSplit()
{
CFileDialog fileDlg(TRUE);
if (fileDlg.DoModal() == IDOK)
{
m_bSplit = TRUE;
m_bSplitByFileSize = TRUE;
m_strFolderName = fileDlg.GetFolderPath();
m_strFileName = fileDlg.GetFileName();
m_uFileSize = 1024 * 1024 * 32;
m_pThread = AfxBeginThread(ThreadFunc, this);
if (m_pThread == nullptr)
{
AfxMessageBox(TEXT("线程函数启动失败!"));
}
}
}
void CFileSplitAndMergeDlg::OnBnClickedButtonMerge()
{
CFileDialog fileDlg(TRUE);
if (fileDlg.DoModal() == IDOK)
{
m_bSplit = FALSE;
m_strFolderName = fileDlg.GetFolderPath();
m_strFileName = fileDlg.GetFileName();
m_strDestFileName = L"myFile.txt";
m_pThread = AfxBeginThread(ThreadFunc, this);
if (m_pThread == nullptr)
{
AfxMessageBox(TEXT("线程函数启动失败!"));
}
}
}
LRESULT CFileSplitAndMergeDlg::OnMyInfo(WPARAM wParam, LPARAM lParam)
{
if (wParam == 0)
{
if (m_bSplit)
{
((CButton *)GetDlgItem(IDC_BUTTON_SPLIT))->EnableWindow(FALSE);
}
else
{
((CButton *)GetDlgItem(IDC_BUTTON_MERGE))->EnableWindow(FALSE);
}
}
else
{
if (m_bSplit)
{
((CButton *)GetDlgItem(IDC_BUTTON_SPLIT))->EnableWindow(TRUE);
}
else
{
((CButton *)GetDlgItem(IDC_BUTTON_MERGE))->EnableWindow(TRUE);
}
}
return 0;
}
UINT CFileSplitAndMergeDlg::ThreadFunc(LPVOID lParam)
{
CFileSplitAndMergeDlg *pDlg = (CFileSplitAndMergeDlg *)lParam;
if (pDlg->m_bSplit)
{
::SendMessageW(pDlg->m_hWnd, WM_MYINFO, 0, 0);
if (pDlg->m_pMySplitAndMergeFile->Split(pDlg->m_strFolderName, pDlg->m_strFileName, pDlg->m_bSplitByFileSize, pDlg->m_uFileSize))
{
AfxMessageBox(TEXT("分割完成"));
}
else
{
AfxMessageBox(TEXT("分割失败"));
}
::SendMessageW(pDlg->m_hWnd, WM_MYINFO, 1, 0);
}
else
{
::SendMessageW(pDlg->m_hWnd, WM_MYINFO, 0, 0);
if (pDlg->m_pMySplitAndMergeFile->Merge(pDlg->m_strFolderName, pDlg->m_strFileName, pDlg->m_strDestFileName))
{
AfxMessageBox(TEXT("合并完成"));
}
else
{
AfxMessageBox(TEXT("合并失败"));
}
::SendMessageW(pDlg->m_hWnd, WM_MYINFO, 1, 0);
}
return 0;
}