目录
拆分:
拆分所使用到的函数与结构体:
主要操作流程:
以下为拆分代码:
合并:
合并所使用到的函数与结构体:
主要操作流程:
以下为合并代码:
将Linux下的文件拆分为多个1MB的小文件,便于发送与上传等操作
umask(int);//用于读写文件后的权限问题
struct stat s_buf;//用于保存文件信息
stat(const char *, stat *);//将路径中的文件信息保存到stat结构体中
S_ISREG(stat.st_mode);//判断是否为文件,若为文件,则返回1,否则返回0
ceil(float);//向上取整,用于判断要拆分多少个文件
int a=wait(int st);//阻塞函数,使父进程进入阻塞状态,等待子进程的结束,避免出现僵尸进程,浪费系统资源,返回值a为接收到的子进程进程号,将子进程结束返回值传给st
perror("");//用于返回错误结果
先读取文件路径,判断所给的是否为文件,若为文件则获取文件大小,除以1MB,判断拆分文件的个数;
然后打开读取文件,使用while循环,批量创建子进程,在子进程中写文件数据,父进程用while循环逐个等待子进程的结束,避免出现僵尸进程
//将文件拆分到指定路径
int SplitFile(string filepath,string tofilepath)
{
int count;//已拆分的文件个数
int size = 0;//预计拆分的文件个数
int readfd = 0;//读文件
int writefd = 0;//写文件
int resbuf = 0;//读到的字符数
char buf[102400] = { 0 };//每个文件的大小
int num = 1;//拆分文件的文件名序号
string writePath;//拆分生成的文件名
int pid = 0;//子进程的pid
int res = 0;//父进程接收到的子进程pid
int status = 0;//接收到子进程完成所返回的信息
struct stat s_buf;//文件信息
umask(0);
stat(filepath.c_str(), &s_buf);
if (!S_ISREG(s_buf.st_mode))
{//不是文件,直接结束
cout << "所给的路径并非文件路径,函数结束" << endl;
return -1;
}
cout << "需要拆分的文件大小为:" << s_buf.st_size << endl;
size = ceil(float(s_buf.st_size / 102400.00));//计算需要拆分文件的个数,向上取整
cout << "需要拆分的文件个数为:" << size << endl;
readfd = open(filepath.c_str(), O_RDONLY, 0777);
if (read < 0)
{
perror("文件读取失败");
return -1;
}
else
{
while ((resbuf = read(readfd, buf, sizeof(buf))) > 0)
{
writePath = tofilepath + to_string(num) + ".tmp";
cout << "写路径:" << writePath << endl;
num++;
pid = fork();
if (pid == 0)
{//子进程做拆分
writefd = open(writePath.c_str(), O_CREAT | O_WRONLY, 0777);
int res = write(writefd, buf, resbuf);
if (res > 0)
{
close(writefd);
bzero(buf, sizeof(buf));
writePath.clear();
}
else
{
perror("读取失败");
}
exit(0);
}
else if (pid > 0)
{
}
}
//父进程
while (count < size)
{
res = wait(&status);
if (res > 0)
{
//cout << "res=" << res << "拆分完毕" << endl;
cout << "已经等待了第" << count << "个子进程" << endl;
count++;
}
}
cout << "所有拆分完毕" << endl;
return 0;
}
}
将所给的文件目录下的所有.tmp文件合并为所提供的文件,注意,合并时必须按照顺序进行合并,否则会出现合并后文件异常的情况,因为无法使用容器的sort函数来进行排序,所以需要自定义类,重载运算符来进行排序。
文件名切分思路:先找到文件所在文件夹的路径及其位置(在本文中为自定义结构体class fileListPath的属性num),再使用string.find(char,int)来找到第一个".",两个位置相减,就是文件名。
DIR * :用于保存文件夹信息
struct dirent* :用于保存文件路径信息
自定义类:class fileListPath;用于文件名的排序
先判断所给的文件夹路径是否为文件夹,再使用while循环遍历文件夹下的所有文件,并排除文件"."与"..",再与文件夹路径拼合成完整的文件路径,便于后续读取,拼合完成后将其装入到容器中
遍历完成后对其进行排序,再使用while循环创建多个子进程进行拼合,父进程用while循环逐个等待子进程的结束,避免出现僵尸进程
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//专门用于文件名排序的类
class fileListPath
{
public:
string PathName;//路径名
int num;//所在文件夹的路径名长度
fileListPath(string name,int num)
{
this->num = num;
this->PathName = name;
}
bool operator > (fileListPath a)
{
int j=this->PathName.find(".", this->num);
string thisnum = this->PathName.substr(this->num,j-this->num);
int aj = a.PathName.find(".", a.num);
string anum = a.PathName.substr(a.num, aj - a.num);
return atoi(thisnum.c_str()) > atoi(anum.c_str());
}
bool operator < (fileListPath a)
{
int j = this->PathName.find(".", this->num);
string thisnum = this->PathName.substr(this->num, j - this->num);
int aj = a.PathName.find(".", a.num);
string anum = a.PathName.substr(a.num, aj - a.num);
return atoi(thisnum.c_str()) < atoi(anum.c_str());
}
};
//需要合并文件夹的路径,和生成合并的文件的路径
int MergeFile(string DirPath,string tofilePath)
{
list pathlist;//用来装路径
list::iterator iter;//用来遍历
DIR* dir;//文件夹信息
struct dirent* d_ent;//文件信息
char buf[102400] = { 0 };//每个文件的大小
int readfd = 0;//读文件描述符
int writefd = 0;//写文件描述符
int res = 0;//返回值
int pid = 0;//进程号
char path[50] = {0};//用于暂存文件名
if ((dir = opendir(DirPath.c_str())) == NULL)
{
perror("文件夹路径不正确");
return -1;
}
while ((d_ent=readdir(dir))!=NULL)
{
if (strcmp(d_ent->d_name, ".") == 0 || strcmp(d_ent->d_name, "..") == 0)
{//排除.和..
continue;
}
if (d_ent->d_type == 8)//判断是不是文件
{//是文件 开始保存路径
const char en = DirPath[DirPath.length() - 1];
if ( !strcmp(&en, "/"))
{//如果最后一个字符有/就不用拼接/了
sprintf(path, "%s%s",DirPath.c_str(),d_ent->d_name);
}
else
{
sprintf(path, "%s/%s", DirPath.c_str(), d_ent->d_name);
}
fileListPath FLP(path, DirPath.length());
pathlist.push_back(FLP);//保存路径到list中
bzero(path, sizeof(path));
}
}
pathlist.sort();
for (iter=pathlist.begin(); iter!=pathlist.end(); iter++)
{
cout << iter->PathName << endl;
}
iter = pathlist.begin();
//开始合并!!
writefd = open(tofilePath.c_str(), O_CREAT|O_WRONLY , 0777);
while (iter != pathlist.end())
{
readfd = open(iter->PathName.c_str(),O_RDONLY,07777);
iter++;
pid = fork();
if (writefd < 0 || readfd < 0)
{
perror("文件操作失败");
}
else
{
if (pid == 0)
{//子进程
while ((res = read(readfd, buf, sizeof(buf))) > 0)
{
write(writefd, buf, res);
bzero(buf, sizeof(buf));
}
close(readfd);
exit(0);
}
else if(pid>0)
{
}
}
}
//父进程一个个等待子进程
int count = 0;
int status = 0;
res = 0;
while (count < pathlist.size())
{
res = wait(&status);
if (res > 0)
{
count++;
}
}
return 0;
}
int main()
{
int res = 0;
res=SplitFile("/root/projects/Warcraft3_End.avi","/root/projects/chaifen/");
if (res >= 0)
{
cout << "拆分成功!!!" << endl;
}
else
{
cout << "拆分失败!" << endl;
}
res=MergeFile("/root/projects/chaifen/", "/root/projects/chaifen/hebing.avi");
if (res >= 0)
{
cout << "合并成功!!!" << endl;
}
else
{
cout << "合并失败!" << endl;
}
return 0;
//by 蓝晓龙
}