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

两种开发方式

  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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值