首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >G级大文件分割器 + 核心源码

G级大文件分割器 + 核心源码

作者头像
phith0n
发布2020-10-15 09:56:32
5530
发布2020-10-15 09:56:32
举报

你还在为下载的裤子很大而notepad++打不开而烦恼吗:

01.jpg
01.jpg

你还在为网盘的单个文件大小上限而发愁吗:

02.jpg
02.jpg

“大文件分割器”到来了,用它可以轻松分割数G的大文件:

03.jpg
03.jpg

网上有很多文件分割器,但效果很差(因为其源码使用的原理不好),很多大型文件(尤其是GB级别的)分割以后可能出现乱码,可能分割以后再次合并时就不是原来的文件了。所以我才自己做了一款文件分割器,分享给各位基友。 至于用处,某些情况下文件太大了确实带来很多麻烦——比如小明前段时间下载的“QQ信封5-10位.txt”,总大小达到了2个多G。小明想看看其中内容,却因为notepad不支持打开这么大的文件而作罢:“file is too big to be open”。用大文件分割器分割以后,就再也不存在这个问题:

04.jpg
04.jpg
05.jpg
05.jpg

界面是MFC写的,关于如何处理GB级别文件,使用的是windows API,内存映射。不细说,大概流程就是:CreateFile - CreateFileMapping - MapViewOfFile - CopyMemory - UnmapViewOfFile - CloseHandle

核心线程代码:

void DevideFile(void * para)
{
	struct Para * pInfo = (struct Para *)para;
	CString strFormat;
	LPCTSTR lpFileName = pInfo->FileName;
	HANDLE hFile;  
	struct FILEINFO  
	{  
		LONGLONG llFileSize;  
		LONG llPartSize;  
		DWORD dwPartNum;  
	};  
	struct FILEINFO fi;  
	fi.llFileSize = 0;  
	fi.llPartSize = 0;  
	fi.dwPartNum = 0;  
	fi.llPartSize = pInfo->llPartSize;
	hFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);  
	if(hFile == INVALID_HANDLE_VALUE)  
	{  
		strFormat.Format("获得文件句柄失败%d。",GetLastError());
		pInfo->pDlg->addInfoBox(strFormat);
		goto __EndPos;
	}  

	LARGE_INTEGER uli = {0};  
	SYSTEM_INFO SysInfo;  
	GetSystemInfo(&SysInfo);  
	DWORD dwGran = SysInfo.dwAllocationGranularity;  

	LONGLONG qwFileOffset = 0;  
	LONGLONG dwBlockBytes = fi.llPartSize;  
	if(GetFileSizeEx(hFile, &uli))  
	{  
		fi.llFileSize = uli.QuadPart;  
		fi.dwPartNum = fi.llFileSize/dwBlockBytes;  
		if((fi.llFileSize % dwBlockBytes) != 0)  
		{  
			fi.dwPartNum += 1;  
		}  
		strFormat.Format("文件:%s 大小为:%I64d KB",lpFileName,uli.QuadPart/1024);
		pInfo->pDlg->addInfoBox(strFormat); 
		strFormat.Format("分块大小:%u KB",(dwBlockBytes/1024));
		pInfo->pDlg->addInfoBox(strFormat); 
	}
	else
	{
		strFormat.Format("没能成功获取源文件大小,请检查源文件是否存在且可读。");
		pInfo->pDlg->addInfoBox(strFormat); 
		goto __EndPos;
	}
	HANDLE hFileMap;  
	hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);//超大文件时该处失败  
	if(hFileMap == NULL)  
	{  
		strFormat.Format("创建文件映射对象句柄失败:%d。",GetLastError());
		pInfo->pDlg->addInfoBox(strFormat);
		CloseHandle(hFile);
		goto __EndPos;
	}  

	LPSTR sTempStr = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAXLENGTH);  
	for(int index = 0;index<fi.dwPartNum;index++)  
	{  
		LPVOID lpMapStartPos;  
		if(fi.llFileSize < dwBlockBytes)  
		{  
			dwBlockBytes = fi.llFileSize;  
		}  
		lpMapStartPos = MapViewOfFile(hFileMap, FILE_MAP_READ, 
			(DWORD)(qwFileOffset >> 32), 
			(DWORD)(qwFileOffset & 0xFFFFFFFF), 
			dwBlockBytes);  
		if(lpMapStartPos == NULL)  
		{  
			strFormat.Format("映射目标文件到内存失败:%d。",GetLastError());
			pInfo->pDlg->addInfoBox(strFormat);
			CloseHandle(hFileMap);  
			CloseHandle(hFile);  
			goto __EndPos;
		}  
		qwFileOffset += dwBlockBytes;  
		fi.llFileSize  -=  dwBlockBytes;  

		sprintf(sTempStr,"%s\\%s_%d.%s", pInfo->OutPath, pInfo->NewName, index + 1, pInfo->FileExt);  
		HANDLE hNewFile = CreateFileA(sTempStr,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);  
		if(hNewFile == INVALID_HANDLE_VALUE)  
		{  
			strFormat.Format("获取分块文件对象句柄失败:%d。",GetLastError());
			pInfo->pDlg->addInfoBox(strFormat);
			UnmapViewOfFile(lpMapStartPos);  
			CloseHandle(hFileMap);  
			CloseHandle(hFile);  
			goto __EndPos;
		}  
		HANDLE hNewFileMap;  
		hNewFileMap = CreateFileMapping(hNewFile,NULL,PAGE_READWRITE,0,dwBlockBytes,NULL);  
		if(hNewFile == NULL)  
		{  
			strFormat.Format("获取分块文件内存映射对象句柄失败:%d。",GetLastError());
			pInfo->pDlg->addInfoBox(strFormat);
			UnmapViewOfFile(lpMapStartPos);  
			CloseHandle(hNewFile);  
			CloseHandle(hFileMap);  
			CloseHandle(hFile);  
			goto __EndPos;
		}  
		LPVOID lpNewFilePos = MapViewOfFile(hNewFileMap,FILE_MAP_WRITE,0, 0, 0);  
		if(lpNewFilePos == NULL)  
		{  
			strFormat.Format("映射分块文件到内存失败:%d。",GetLastError());
			pInfo->pDlg->addInfoBox(strFormat);
			UnmapViewOfFile(lpMapStartPos);  
			CloseHandle(hNewFileMap);  
			CloseHandle(hNewFile);  
			CloseHandle(hFileMap);  
			CloseHandle(hFile);  
			goto __EndPos;
		}  

		CopyMemory(lpNewFilePos,lpMapStartPos,dwBlockBytes);  
		strFormat.Format("分块文件%s成功生成。",sTempStr);
		pInfo->pDlg->addInfoBox(strFormat);
		UnmapViewOfFile(lpMapStartPos);  
		UnmapViewOfFile(lpNewFilePos);  
		CloseHandle(hNewFileMap);  
		CloseHandle(hNewFile);  
	}  
	CloseHandle(hFileMap);  
	CloseHandle(hFile);  
	pInfo->pDlg->addInfoBox("恭喜,文件分割成功!");
	
__EndPos:
	//后续处理
	return ;
}

关于内存映射技术,在此有详细说明:http://www.oschina.net/question/54100_26210

但程序有点问题在于,有时候可能会存在内存不足不能开始分割的问题,windows错误代码为8. 但问题似乎确实跟你此时电脑的状态有关。昨晚我测试时候将5G的文件分割成500M的文件时候出现错误,但今早把8G的文件分割成500M的时候没有任何问题。我电脑内存是4G,或许也跟硬盘有关?

于是我又做了一个64位版本,问题得到了解决,没有再出现内存不足的问题。所以大家如果分割超大文件出错的话可以试试x64版本的,我都放在压缩包里了。

下载: http://pan.baidu.com/s/1ntK4Ckh

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档