Windows Practice_文件_文件分割器(三)

来源:互联网 发布:linux 线程退出 编辑:程序博客网 时间:2024/06/17 09:08

两种开发方式

  1. 瀑布式开发
    有需求 -> 分析 -> 建模 -> 编码 -> 维护 所有的类全部是自己设计编码的
  2. 敏捷开发
    需求 -> 编码 -> 重构(建模) -> 编码 需求总是变化的 -> 代码也需要变化
    所谓的敏捷开发就是拿着开源项目修改为自己的项目,随着时间的推移,改变的越来越多的内容,最后可能将原来开源项目中的所有内容都改为自己的内容。

当前类的性质,
类方法及类成员设计的时候
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;}