Linux下使用C++采用父子进程完成文件的拆分与合并

目录

拆分:

拆分所使用到的函数与结构体:

主要操作流程:

以下为拆分代码:

合并:

合并所使用到的函数与结构体:

主要操作流程:

以下为合并代码:


拆分:

将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 <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cstdlib>
#include <termios.h>
#include <dirent.h>
#include <string>
#include <cmath>
#include <list>
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<fileListPath> pathlist;//用来装路径
	list<fileListPath>::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;

}

  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个不同的ID

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值