G级大文件分割器 + 核心源码
你还在为下载的裤子很大而notepad++打不开而烦恼吗:
你还在为网盘的单个文件大小上限而发愁吗:
“大文件分割器”到来了,用它可以轻松分割数G的大文件:
网上有很多文件分割器,但效果很差(因为其源码使用的原理不好),很多大型文件(尤其是GB级别的)分割以后可能出现乱码,可能分割以后再次合并时就不是原来的文件了。所以我才自己做了一款文件分割器,分享给各位基友。 至于用处,某些情况下文件太大了确实带来很多麻烦——比如小明前段时间下载的“QQ信封5-10位.txt”,总大小达到了2个多G。小明想看看其中内容,却因为notepad不支持打开这么大的文件而作罢:“file is too big to be open”。用大文件分割器分割以后,就再也不存在这个问题:
界面是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
- Go web之旅(路由篇)
- Golang插入排序
- Golang写的并行排序算法
- Go中调用dll示例
- python 序列化数据:pickle与json ,dumps与loads
- golang继承,和多态
- python 利用random生成验证码与MD5码加密过程
- Java内部类的继承
- Java继承类中static成员函数的重写
- Search for a range寻找上下界-Leetcode
- Basic Calculator 基本计算器-Leetcode
- python yield函数深入浅出理解
- 十分钟搞定 Tensorflow 服务
- datapump跨平台升级迁移的总结 (r8笔记第77天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 谈谈类加载器
- Android中AlarmManager+Notification实现定时通知提醒功能
- Java垃圾回收相关面试题
- Android中backgroundDimEnabled的作用
- 甲基化相关的习题背景补充
- Android 完全退出的实例详解
- Android 双击Back键退出应用的实现方法
- 2020最全Java面试题--基础篇
- Android开发之背景动画简单实现方法
- 15.深入k8s:Event事件处理及其源码分析
- 说一说 HashMap 底层数据结构
- 详解Android Service 使用时的注意事项
- Android自定义View实现QQ运动积分转盘抽奖功能
- 请简述Spring JDBC是如何进行配置的
- Java高频面试题 -- 静态