文件分割器实现时注意的几点

分割文件的头信息结构体的设计,如果里面需要存储字符串的信息,我们必须使用字符串数组来存储,而不能使用类似于CString、string等字符串对象来存储,因为使用这些对象在存储的时候还好,可以知道它的长度进行文件的写入,但是在读取的时候就会出现问题了,因为不知道读取多少。
解决方法有两个:
1. 在头文件信息结构体中加上构造函数和一些其它的辅助函数(这样就相当于类的功能了,反正我是不推荐使用),然后对结构体中的成员变量进行操作;
2. 专门有一些操作这个结构体的函数,比如初始化文件头部信息函数、获取文件头部信息(一个变量对应一个函数)等。
在分割的时候还会出现一些细节的问题:
在读取的时候不知道什么时候分割完成,因为我们还要在最后一个分割文件的头信息加上是最后一个分割文件的标识。这个问题会出现在:比如每次读取10个字节,待分割文件恰好有20字节,正好读取两次,每一次都是读取10个字节,所以我们不能够通过最后一次读取的字节个数来判断是否读取到最后一个字节,这时还要借助于文件信息中的文件长度来做比较,通过读取总字节的个数和原来字节的总个数相比较,当读取到的总字节大于等于原字节数的时候,就认为读取完成,可以做最后一个文件的标记了。

编程规范

在能够不使用指针的情况下不去使用指针,除非逼不得已的时候才去使用指针。绝大多数错误都是因为使用指针才出现的。
函数命名的时候不要和系统API重名。
代码相同的时候尽量不要去复制粘贴,这样很容易出错,还有就是如果真的出现重复代码的时候,那么我们就需要重构了。

文件分割的简单封装

// FileSplitAndMerge.h文件#ifndef _MYFILESPLITANDMERGE_H_
#define _MYFILESPLITANDMERGE_H_#include <vector>
#include <Windows.h>
#include <afx.h>/**
* \brief 每个分割文件的头信息,其中包括了:
* wFlag 文件标志
* strFirstFileName 所有分割文件中的第一个文件名
* strNextFileName 下一个分割文件的文件名
* strOriginalFileName 原始文件的文件名
* uValidDataLength 有效的数据长度
*/
struct PARTFILEHEADERINFO
{WORD wFlag;WCHAR strFirstFileName[100];WCHAR strNextFileName[100];WCHAR strOriginalFileName[100];UINT uValidDataLength;
};class CMyPartFile : public CFile
{
public:CMyPartFile();~CMyPartFile();void SetPartFileHeaderInfo(WORD wFlag, const CString &strFirstFileName, const CString &strNextFileName, const CString &strOriginalFileName, const UINT uReadBytesNumber);/*** \brief 获取存有有效数据的内存地址* \return 返回存有有效数据的内存地址*/BYTE *GetValidData();BOOL SaveValidDataToFile(const CString &strFolderName, const CString &strFileName, const BYTE* pData);BOOL LoadFile(const CString &strFilePath);WCHAR *GetFirstFileName();WCHAR *GetNextFileName();WCHAR *GetOriginalFileName();UINT GetValidFileLength() const;/*** \brief 判断是否是我们自己的分割的文件* \return 如果是我们分割的文件标志则返回TRUE,否则返回FALSE*/BOOL IsValidFile() const;
private:PARTFILEHEADERINFO m_partFileHeaderInfo;/*** \brief 生成新的分割文件存放的目录*/CString m_strNewFolderName;CString m_strFilePath;BYTE *m_pValidData;
};class CMyFileSplitAndMerge
{
public:CMyFileSplitAndMerge();~CMyFileSplitAndMerge();
public:/*** \brief 将原来的大文件按照指定的大小分割成一个个小文件* \param strFolderName 文件夹名字* \param strOriginalFileName 文件名字* \param uSplitFileSize 分割文件大小* \return 文件分割成功返回TRUE,否则返回FALSE*/BOOL Split(const CString &strFolderName, const CString &strOriginalFileName, const UINT uSplitFileSize);/*** \brief 根据选定的任意一个分割后的文件名,将这些所有的分割文件合并成成原来的文件* \param strFolderName 文件夹名字* \param strPartFileName 分割的任意一个文件的名字* \return 文件合并成功返回TRUE,否则返回FALSE*/BOOL Merge(const CString &strFolderName, const CString &strPartFileName);private:/*** \brief 获取所有的分割的文件* \param strFolderName 文件夹名字* \param strPartFileName 分割的任意一个文件的名字* \return 如果全部找到分割的文件返回TRUE,否则返回FALSE*/BOOL GetAllPartFile(const CString &strFolderName, const CString &strPartFileName);private:std::vector<CMyPartFile *> m_vecAllPartFile;CString m_strOriginalFileName;
};
#endif!//_MYFILESPLITANDMERGE_H_
// FileSplitAndMerge.cpp文件#include <stdafx.h>
#include "MyFileSplitAndMerge.h"CMyPartFile::CMyPartFile(): m_pValidData(nullptr)
{
}CMyPartFile::~CMyPartFile()
{if (m_pValidData){delete[] m_pValidData;}
}void CMyPartFile::SetPartFileHeaderInfo(WORD wFlag, const CString& strFirstFileName, const CString& strNextFileName, const CString& strOriginalFileName, const UINT uReadBytesNumber)
{m_partFileHeaderInfo.wFlag = MAKEWORD('P', 'o');wcscpy_s(m_partFileHeaderInfo.strFirstFileName, strFirstFileName);wcscpy_s(m_partFileHeaderInfo.strNextFileName, strNextFileName);wcscpy_s(m_partFileHeaderInfo.strOriginalFileName, strOriginalFileName);m_partFileHeaderInfo.uValidDataLength = uReadBytesNumber;wchar_t *pTemp = nullptr;WCHAR str[MAXBYTE] = { 0 };wcscpy_s(str, m_partFileHeaderInfo.strOriginalFileName);m_strNewFolderName = wcstok_s(str, L".", &pTemp);
}BYTE* CMyPartFile::GetValidData()
{CFileException fileException;if (Open(m_strFilePath, CFile::modeRead|CFile::typeBinary, &fileException)){try{m_pValidData = new BYTE[m_partFileHeaderInfo.uValidDataLength];}catch (const std::bad_alloc &e){MessageBoxA(nullptr, e.what(), "温馨提示", MB_OK);}memset(m_pValidData, 0, m_partFileHeaderInfo.uValidDataLength);Seek(sizeof(PARTFILEHEADERINFO), CFile::begin);Read(m_pValidData, m_partFileHeaderInfo.uValidDataLength);Close();}else{m_pValidData = nullptr;}return m_pValidData;
}BOOL CMyPartFile::SaveValidDataToFile(const CString &strFolderName, const CString &strFileName, const BYTE* pData)
{BOOL bRet = FALSE;CreateDirectory(strFolderName + TEXT("\\") + m_strNewFolderName, nullptr);CString strFilePath = strFolderName + TEXT("\\") + m_strNewFolderName + TEXT("\\") + strFileName;CFileException cFileException;if (Open(strFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary, &cFileException)){Write(&m_partFileHeaderInfo, sizeof(PARTFILEHEADERINFO));Write(pData, m_partFileHeaderInfo.uValidDataLength);Close();bRet = TRUE;}else{TCHAR strErrorMessage[MAXBYTE] = { 0 };cFileException.GetErrorMessage(strErrorMessage, MAXBYTE);MessageBox(nullptr, strErrorMessage, L"温馨提示", MB_OK);}return bRet;
}BOOL CMyPartFile::LoadFile(const CString& strFilePath)
{BOOL bRet = FALSE;m_strFilePath = strFilePath;TCHAR strErrorMessage[MAXBYTE] = { 0 };CFileException fileException;if (Open(m_strFilePath, CFile::modeRead|CFile::typeBinary, &fileException)){UINT uReadByteNumber = Read(&m_partFileHeaderInfo, sizeof(PARTFILEHEADERINFO));if (uReadByteNumber != sizeof(PARTFILEHEADERINFO)){fileException.GetErrorMessage(strErrorMessage, MAXBYTE);MessageBox(nullptr, strErrorMessage, TEXT("温馨提示"), MB_OK);}else{bRet = TRUE;}Close();}else{fileException.GetErrorMessage(strErrorMessage, MAXBYTE);MessageBox(nullptr, strErrorMessage, TEXT("温馨提示"), MB_OK);}return bRet;
}WCHAR* CMyPartFile::GetFirstFileName()
{return m_partFileHeaderInfo.strFirstFileName;
}WCHAR* CMyPartFile::GetNextFileName()
{return m_partFileHeaderInfo.strNextFileName;
}WCHAR* CMyPartFile::GetOriginalFileName()
{return m_partFileHeaderInfo.strOriginalFileName;
}UINT CMyPartFile::GetValidFileLength() const
{return m_partFileHeaderInfo.uValidDataLength;
}BOOL CMyPartFile::IsValidFile() const
{return m_partFileHeaderInfo.wFlag == MAKEWORD('P', 'o');
}CMyFileSplitAndMerge::CMyFileSplitAndMerge()
{
}CMyFileSplitAndMerge::~CMyFileSplitAndMerge()
{
}BOOL CMyFileSplitAndMerge::Split(const CString& strFolderName, const CString& strOriginalFileName, const UINT uFileSize)
{BOOL bRet = FALSE;CString strFileOriginalFilePath = strFolderName + TEXT("\\") + strOriginalFileName;CFile file;CFileException fileException;if (file.Open(strFileOriginalFilePath, CFile::modeRead|CFile::typeBinary)){ULONGLONG ullFileLength = file.GetLength(), ullReadFileLength = 0;UINT uReadBytesNumber, uPartFileCount = 0;CString strFirstFileName = TEXT("0.part"), strCurFileName, strNextFileName;BYTE *pData = new BYTE[uFileSize];memset(pData, 0, uFileSize);while (true){PARTFILEHEADERINFO partFileHeaderInfo = { 0 };uReadBytesNumber = file.Read(pData, uFileSize);ullReadFileLength += uReadBytesNumber;strCurFileName.Format(TEXT("%d.part"), uPartFileCount);if (ullReadFileLength >= ullFileLength){strNextFileName = L"NULL";bRet = TRUE;}elsestrNextFileName.Format(TEXT("%d.part"), ++uPartFileCount);CMyPartFile myPartFile;myPartFile.SetPartFileHeaderInfo(MAKEWORD('P', 'o'), strFirstFileName, strNextFileName, strOriginalFileName, uReadBytesNumber);myPartFile.SaveValidDataToFile(strFolderName, strCurFileName, pData);if (bRet)   break;memset(pData, 0, uFileSize);}delete[] pData;file.Close();}elseMessageBox(nullptr, TEXT("打开文件失败"), TEXT("温馨提示"), MB_OK);return bRet;
}BOOL CMyFileSplitAndMerge::Merge(const CString& strFolderName, const CString& strPartFileName)
{BOOL bRet = FALSE;if (GetAllPartFile(strFolderName, strPartFileName)){CString strOriginalFilePath = strFolderName + L"\\" + m_strOriginalFileName;CFile file(strOriginalFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);for (auto value : m_vecAllPartFile){file.Write(value->GetValidData(), value->GetValidFileLength());bRet = TRUE;}file.Close();}return bRet;
}BOOL CMyFileSplitAndMerge::GetAllPartFile(const CString& strFolderName, const CString& strPartFileName)
{BOOL bRet = FALSE;CString strFirstFileName = TEXT(""), strCurFileName, strNextFileName;CMyPartFile myPartFile;if (myPartFile.LoadFile(strFolderName + L"\\" + strPartFileName)){strFirstFileName = myPartFile.GetFirstFileName();// 下面是从第一个文件开始,一个一个的往后遍历,如果没有找到文件结尾的标志“NULL”,那么查找失败strCurFileName = strFirstFileName;while (true){CMyPartFile *pMyPartFile = new CMyPartFile;if (pMyPartFile->LoadFile(strFolderName + L"\\" + strCurFileName)){if (pMyPartFile->IsValidFile()){m_vecAllPartFile.push_back(pMyPartFile);}else{break;}strNextFileName = pMyPartFile->GetNextFileName();if (strNextFileName != TEXT("NULL")){strCurFileName = strNextFileName;}else{m_strOriginalFileName = pMyPartFile->GetOriginalFileName();bRet = TRUE;break;}}else{break;}}}return bRet;
}

虽然上面实现了类的封装的功能,但是还是不规范,因为CMyPartFile这个类的功能比较模糊,它在使用的时候感觉不太好用,所以还需要对上面的类更进一步的封装和重构。这要到下一节再改进。

Windows Practice_文件_文件分割器(二)相关推荐

  1. 怎么用stata打开dta文件_第三十二章、用c语言打开文件

    这一章我们先来了解一下文件是什么? 一个文件通常就是磁盘上的一段命名的存储区.如我们在C语言编程中经常引入的stdio.h就是一个包含一些有用信息的文件的名称.当然对于操作系统来说,文件就会更复杂一些 ...

  2. Python_文件IO_CSV文件_文件交互_OS模块_异常(13)

    目录: 一.文件介绍 二.文件读写简单操作 三.文件权限 四.文件操作 1.读操作 2.写操作 3.CSV文件读写 4.with 5.文件交互扩展 6.文件复制 五.os模块 六.异常 1.什么是异常 ...

  3. 知道路程时间求加速度_凸轮分割器的出力轴加速度是怎么算的

    凸轮分割器的出力轴,也就是箱体内部的出力转塔是在入力轴的弧面凸轮肋的作用下进行的,要计算出力轴的加速度,就要先考虑驱动出力轴产生加速度的入力轴及相关的影响因素. 分割器凸轮进口原材料 我们知道,无论是 ...

  4. pythonshell压缩文件_文件夹压缩成zip格式

    前言: 在最近的后台开发工作中,需要将服务器的指定文件夹压缩,然后传输到前台.shell的zip命令可以很方便的实现该需求,python也有对应的模块,这里简要记录一下使用两种方式压缩文件的方法. s ...

  5. .hpp文件_文件上传漏洞另类绕过技巧及挖掘案例全汇总

    文件上传漏洞作为获取服务器权限最快的方式,虽然相关资料很多,但很多人对上传校验方式.如何针对性绕过检测.哪种上传和解析的场景会产生危害等还是比较模糊.本文作一些阐述,然后补充一些除了上传webshel ...

  6. 局域网传文件_文件搜索神器Everything使用系列教程之——文件互传篇

    本文接上篇 文件搜索神器Everything使用系列教程之--搜索篇. 众所周知,Everything是一款文件搜索软件,它如何做文件互传呢? 别看Everything小巧,它竟然内置了FTP服务器和 ...

  7. php 解压有密码的zip文件_文件解压引发的getshell

    声明! 本文仅供学习和研究,由于传播.利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,海青实验室及文章作者不承担任何责任.安全狗海青实验室拥有此文章的修改和解释权,如欲转 ...

  8. aps后缀是什么文件_文件后缀大全

    .APS : 存放二进制资源的中间文件, VC 把当前资源文件转换成二进制格式, 并存放在 APS 文件中,以加快资源装载速度.资源辅助文件. .BMP :位图资源文件. .BSC :浏览信息文件,由 ...

  9. 后缀是php,php是什么文件_文件后缀php是什么意思

    摘要 腾兴网为您分享:文件后缀php是什么意思,桌面日历,中信金通,易信,小睡眠等软件知识,以及语音朗读,安卓投屏电脑软件,c#编程软件,ppt批量转pdf,魅族服务中心,微学院,手机照片墙图片,牛账 ...

最新文章

  1. 结对编程-四则运算生成程序-GUI界面
  2. 【Android 应用开发】Android UI 设计之 TextView EditText 组件属性方法最详细解析
  3. Windows Sockets错误标识及对应解释
  4. java虚拟机内存监控_深入理解JVM虚拟机9:JVM监控工具与诊断实践
  5. java session 详解
  6. SQL 的 left join 和 right join
  7. Git GUI基本操作
  8. 023、JVM实战总结:一步一图:那JVM老年代垃圾回收器CMS工作时,内部又干了些啥?
  9. 《Linux命令行与shell脚本编程大全 第3版》高级Shell脚本编程---35
  10. 推荐一款强大的国产开源监控系统!
  11. arcpy 查看arcgis的产品类型、产品许可与安装信息
  12. 捷联惯导系统学习3.3(引力位函数)
  13. 查纸张开数软件怎么样
  14. Linux查看目录busy,Linux中遇到device is busy的处理方法
  15. 计算机组装流程是什么,组装电脑的步骤
  16. 在linux下如何显示隐藏文件
  17. 驱动程序如何手动卸载与更新
  18. 计算机控制面板包含的管理类别有什么,如何设置控制面板分类
  19. 前端推荐的学习资源网站
  20. 学校招聘行政老师的计算机能力测试,【】计算机教师招聘试题(25页)-原创力文档...

热门文章

  1. springboot+dubbo+zookeeper怎么设置熔断器并调用
  2. Agisoft Metashape 电力线检测
  3. 11.定时任务定时线程池详解
  4. 技术人的灵魂3问,阿里工程师如何解答?
  5. (11/∞)每日一练{1.将一张100元钞票换成等值的10元,5元,2元和1元的小钞,每次换成40张小钞,要求每一种小钞都要有,编程求出所有可能的换法总数输出并输出各换法的组合。}
  6. 【甲午年正月初五】测试使用的软件
  7. 【Python基础】第十八篇 | JSON文件的处理
  8. 简单介绍一下qsort函数
  9. C语言函数——qsort函数的使用
  10. 鼠标样式:cursor属性值(含自定义光标图案) - 代码篇