文件分割的意义
有以下几点需要进行文件分割:
- 以前的硬盘格式是FAT32,也是意味着最大的内存放的单个文件是4GB,如果文件超过4GB,就需要进行分割成小于4GB的文件才能存储到硬盘上;
- 网络虚度比较慢,并且还会出现中断,一旦中断,下载的文件就会失效。
我们在做分割时候,除了考虑分割外,还需要考虑合并,否则分割也就没有意义了。
CFile函数注意事项
CFile默认打开的是文本格式,这不符合文件风格的要求,文件分割需要使用二进制进行读写。
一般来说:BYTE表示的数据,而char代表一个字符。
文件切割代码
BOOL CFileCutterDemoDlg::CutFile(const CString& strFolderName, const CString& strOriginalFileName, const UINT uFileCutSize)
{
BOOL bRet = FALSE;
CFile cFileRead(strFolderName + L"\\" + strOriginalFileName, CFile::modeRead | CFile::typeBinary);
//const UINT FILESIZE = 10;
DWORD dwFileCount = 0;
while (true)
{
BYTE byteArray[uFileCutSize] = { 0 };
DWORD dwReadNum = cFileRead.Read(byteArray, uFileCutSize);
CString strCurWriteFileName;
CString strTempWriteFileName;
strCurWriteFileName.Format(L"%d.part", dwFileCount++);
CString strWriteFilePath = strFolderName + L"\\" + strCurWriteFileName;
FileHeader fileHeader = { 0 };
wcscpy_s(fileHeader.strFlag, L"Po");
if (dwReadNum < uFileCutSize)
{
strTempWriteFileName.Format(L"%d.part", dwFileCount - 2);
wcscpy_s(fileHeader.strPrevFileName, strTempWriteFileName.GetString());
wcscpy_s(fileHeader.strNextFileName, L"last");
CFile cFileWrite(strWriteFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
cFileWrite.Write(&fileHeader, sizeof(FileHeader));
cFileWrite.Write(byteArray, dwReadNum);
cFileWrite.Close();
bRet = TRUE;
break;
}
else
{
if (dwFileCount == 1)
{
// 说明是第一个文件,它的前面是没有文件的
wcscpy_s(fileHeader.strPrevFileName, L"first");
strTempWriteFileName.Format(L"%d.part", dwFileCount);
wcscpy_s(fileHeader.strNextFileName, strTempWriteFileName.GetString());
}
else
{
strTempWriteFileName.Format(L"%d.part", dwFileCount - 2);
wcscpy_s(fileHeader.strPrevFileName, strTempWriteFileName);
strTempWriteFileName.Format(L"%d.part", dwFileCount);
wcscpy_s(fileHeader.strNextFileName, strTempWriteFileName.GetString());
}
CFile cFileWrite(strWriteFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
cFileWrite.Write(&fileHeader, sizeof(FileHeader));
cFileWrite.Write(byteArray, dwReadNum);
cFileWrite.Close();
}
}
cFileRead.Close();
return bRet;
}
文件合并代码
struct PARTFILEHEADER
{
WORD m_wFlag;
WCHAR m_strPrevFileName[100];
WCHAR m_strNextFileName[100];
UINT m_uSourceFileSize;
};
BOOL CFileCutterDemoDlg::MyFindFirstFileName(const CString &strFolderName, const CString &strCurFileName, CString &strFirstFile) const
{
BOOL bRet = FALSE;
CString strFilePath = strFolderName + L"\\" + strCurFileName;
FileHeader fileHeader = { 0 };
CFile file(strFilePath.GetString(), CFile::modeRead | CFile::typeBinary);
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
while (true)
{
if (wcscmp(fileHeader.strFlag, L"Po") == 0)
{
if (wcscmp(fileHeader.strPrevFileName, L"first") == 0)
{
// 找到第一个文件名字
strFilePath = strFolderName + L"\\" + fileHeader.strNextFileName;
file.Open(strFilePath, CFile::modeRead | CFile::typeBinary);
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
strFirstFile = fileHeader.strPrevFileName;
bRet = TRUE;
break;
}
else
{
// 更新文件头信息
strFilePath = strFolderName + L"\\";
strFilePath += fileHeader.strPrevFileName;
file.Open(strFilePath.GetString(), CFile::modeRead|CFile::typeBinary);
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
}
}
else
{
break;
}
}
return bRet;
}
BOOL CFileCutterDemoDlg::MyFindAllFileName(const CString& strFolderName, const CString& strFirstFile, std::vector<CString> &vecFileName) const
{
BOOL bRet = FALSE;
CString strFileName = strFirstFile;
CString strFilePath = strFolderName + L"\\" + strFileName;
FileHeader fileHeader = { 0 };
CFile file(strFilePath, CFile::modeRead | CFile::typeBinary);
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
while (true)
{
if (wcscmp(fileHeader.strFlag, L"Po") == 0)
{
// 将当前的文件路径加入到vec中
vecFileName.push_back(strFileName);
if (wcscmp(fileHeader.strNextFileName, L"last") == 0)
{
bRet = TRUE;
break;
}
// 更新header
strFileName = fileHeader.strNextFileName;
strFilePath = strFolderName + L"\\" + strFileName;
file.Open(strFilePath, sizeof(FileHeader));
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
}
else
{
break;
}
}
return bRet;
}
BOOL CFileCutterDemoDlg::MyFindFrontAllFileName(const CString& strFolderName, const CString& strCurFileName, std::vector<CString> &vecFrontAllFilePath) const
{
BOOL bRet = FALSE;
CString strFileName = strCurFileName;
CString strFilePath = strFolderName + L"\\" + strFileName;
FileHeader fileHeader = { 0 };
CFile file(strFilePath, CFile::modeRead | CFile::typeBinary);
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
while (true)
{
if (wcscmp(fileHeader.strFlag, L"Po") == 0)
{
// 将当前的文件路径加入到vec中
vecFrontAllFilePath.push_back(strFileName);
if (wcscmp(fileHeader.strPrevFileName, L"first") == 0)
{
bRet = TRUE;
std::reverse(vecFrontAllFilePath.begin(), vecFrontAllFilePath.end());
vecFrontAllFilePath.pop_back(); // 不包括当前的文件路径
break;
}
// 更新header
strFileName = fileHeader.strPrevFileName;
strFilePath = strFolderName + L"\\" + strFileName;
file.Open(strFilePath, sizeof(FileHeader));
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
}
else
{
break;
}
}
return bRet;
}
BOOL CFileCutterDemoDlg::MyFindBackAllFileName(const CString& strFolderName, const CString& strCurFileName, std::vector<CString>& vecBackAllFilePath) const
{
BOOL bRet = FALSE;
CString strFileName = strCurFileName;
CString strFilePath = strFolderName + L"\\" + strFileName;
FileHeader fileHeader = { 0 };
CFile file(strFilePath, CFile::modeRead | CFile::typeBinary);
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
while (true)
{
if (wcscmp(fileHeader.strFlag, L"Po") == 0)
{
// 将当前的文件路径加入到vec中
vecBackAllFilePath.push_back(strFileName);
if (wcscmp(fileHeader.strNextFileName, L"last") == 0)
{
bRet = TRUE;
break;
}
// 更新header
strFileName = fileHeader.strNextFileName;
strFilePath = strFolderName + L"\\" + strFileName;
file.Open(strFilePath, sizeof(FileHeader));
file.Read(&fileHeader, sizeof(FileHeader));
file.Close();
}
else
{
break;
}
}
return bRet;
}
void CFileCutterDemoDlg::MyMergeFile(const CString& strFolderName, const std::vector<CString> vecFileName) const
{
CString strNewFilePath = strFolderName + L"\\" + L"mergeFile.txt";
CFile fileNew(strNewFilePath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
const UINT FILESIZE = 10;
for (auto file_name : vecFileName)
{
BYTE byteArray[FILESIZE] = { 0 };
CString strFilePath = strFolderName + L"\\" + file_name;
CFile file(strFilePath, CFile::modeRead | CFile::typeBinary);
file.Seek(sizeof(FileHeader), CFile::begin);
UINT uReadNum = file.Read(byteArray, FILESIZE);
file.Close();
fileNew.Write(byteArray, uReadNum);
}
fileNew.Close();
}
void CFileCutterDemoDlg::OnBnClickedButtonMerge()
{
// 首先打开一个文件,读取信息头
CFileDialog fileDlg(TRUE);
if (fileDlg.DoModal() == IDOK)
{
// 是要合并的文件,可以开始遍历文件夹,找到所有的文件,然后按照顺序排列
//首先分成两个方向, 首先,挨个向前遍历,找到第一个文件,如果找不到第一个文件,则文件缺失
// 然后再从第一个文件向后遍历并记录文件路径,如果找不到最后文件,则文件缺失
// 文件数量完整性标志
CString strFirstFileName;
std::vector<CString> vecAllFileName;
std::vector<CString> vecFrontAllFileName;
std::vector<CString> vecBackAllFileName;
do
{
找第一个文件
//if (!MyFindFirstFileName(fileDlg.GetFolderPath(), fileDlg.GetFileName(), strFirstFileName))
//{
// // 没有找到第一个文件,查找失败
// MessageBox(TEXT("没有找到第一个文件名字!"));
// break;
//}
//if (!MyFindAllFileName(fileDlg.GetFolderPath(), strFirstFileName, vecAllFilePath))
//{
// break;
//}
if (!MyFindFrontAllFileName(fileDlg.GetFolderPath(), fileDlg.GetFileName(), vecFrontAllFileName))
{
// 没有找到第一个文件,查找失败
MessageBox(TEXT("没有找到第一个文件名字!"));
break;
}
if (!MyFindBackAllFileName(fileDlg.GetFolderPath(), fileDlg.GetFileName(), vecBackAllFileName))
{
// 没有找到最后个文件,查找失败
MessageBox(TEXT("没有找到最后个文件名字!"));
break;
}
for (auto filePath : vecFrontAllFileName)
vecAllFileName.push_back(filePath);
for (auto filePath : vecBackAllFileName)
vecAllFileName.push_back(filePath);
MyMergeFile(fileDlg.GetFolderPath(), vecAllFileName);
} while (false);
}
}