多进程实现文件拷贝
复制方式
./processsrc_file process_num(进程数名称输入:0~100)
有两个.c
文件,分别是ProcessCopy.c
和mycp.c
,其中mycp.c
是一个拷贝文件,默认只有一个进程,具体拷贝程序的流程数可以通过传参来确定。
ProcessCopy.c 程序
该程序主要分为创建子流程,ECEC函数重载mycp.c
函数,回收子进程空间,错误处理等几部分。
在子进程中进行拷贝时,通过<ProcessNum
来文件子进程进行拷贝。
mycp.c程序
1.该程序主要完成对文件的拷贝工作。
2.拷贝的进程数可以通过EXEC函数传递,传递时将进程编号一并传递,来辨别是时间子进程,以便计算偏移位置。
3.通过lseek来计算子过程读取和写入的轨迹位置。
4.在拷贝时,需要计算过程中需要拷贝源的字节数wNum,由于文件的总字节数特别能整除过程数,因此如果不能整除需要wNum+1处理。
5.设置每个flag来标记进程已经拷贝的字节数,当flag>wNum
时,需要设置拷贝的字节数为wSize = wSize - (flag-rsize)
,复制完成后退出,此过程复制工作完成
拷贝文件进程
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
//错误码
enum ecode_err{
argument_list_err,
src_open_err,
des_open_err,
cop_fin
};
int main(int argc,char **argv)
{
//错误处理
if(argc < 3)
{
printf("请输入源文件和目标文件!\n");
exit(argument_list_err);
}
int ProcessNum = 1;
int nCount = 0;//标记第几个进程
//字符转数字
if(argc > 4)
{
ProcessNum = atoi(argv[3]);
nCount = (int)*argv[4];
}
//文件描述符
int sfd = open(argv[1],O_RDONLY);//源文件
if(sfd < 0)
{
perror("open src error!\n");
exit(src_open_err);
}
int dfd = open(argv[2],O_WRONLY | O_CREAT,0664);//目标文件
if(dfd < 0)
{
perror("open des error!\n");
exit(des_open_err);
}
//计算文件大小
int fileSize = lseek(sfd,0,SEEK_END);
//计算子进程需要拷贝的起点和大小
int wNum = fileSize/ProcessNum;
//文件可能不会被进程整除,因此不能除近时每个进程多拷贝一个
wNum = fileSize%ProcessNum == 0 ? wNum : wNum+1;
//读取数据缓冲区大小
char buffer[8192] = {0};
//读取的字节数和每个进程总共读取字节数标志
int rsize;
int flag = 0;
//设置每个进程读取和写入的偏移指针位置
int rseek = lseek(sfd,wNum*nCount,SEEK_SET);
int wseek = lseek(dfd,wNum*nCount,SEEK_SET);
while((rsize = read(sfd,buffer,sizeof(buffer)))!= 0)
{
flag += rsize;
if(flag >= wNum)
{
//如果读取的数据大于要每个进程要写入的数据wNum
rsize = wNum - (flag - rsize);
write(dfd,buffer,rsize);
//每一个进程拷贝结束后都要关闭自己的文件,描述符
close(sfd);
close(dfd);
break;
//exit(red_fin);
}
write(dfd,buffer,rsize);
}
//每一个进程拷贝结束后都要关闭自己的文件,描述符
close(sfd);
close(dfd);
return cop_fin;
}
父进程创建的子进程重载(exec)拷贝进程
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
//错误码
enum ecode_err{
argument_list_err = 3,
argument_many,
ProcessNum_err,
fork_err,
};
int main(int argc,char **argv)
{
//校验传入参数
if(argc < 3)
{
printf("请输入要拷贝的源文件和目标文件!(进程数可选择是否输入:0~100)\n");
exit(argument_list_err);
}
if(argc > 4)
{
printf("最多传三个参数!\n");
exit(argument_many);
}
int ProcessNum = 5;//默认创建5个进程
if(argc == 4)
{
ProcessNum = atoi(argv[3]);
}
//校验用户输入的线程数
if(ProcessNum <= 0 || ProcessNum >= 100)
{
printf("请输入0~100之间内的进程数\n");
exit(ProcessNum_err);
}
/*-----------------------------------开始拷贝------------------------------------*/
//创建子进程
pid_t pid;
int i;
for(i = 0;i < ProcessNum;i++)
{
pid = fork();
//子进程跳出循环,只有父进程来创建进程
if(pid == 0)
break;
}
if(pid < 0)
{
perror("parent call fork fail...\n");
exit(fork_err);
}
/*---------子进程拷贝--------------*/
if(i < ProcessNum)//子进程
{
char *argv1[] = {"copy",argv[1],argv[2],argv[3],(char*)&i,NULL};
int ecode = execv("copy",argv1);
}
/*-----------------------------回收子进程空间------------------------------------------*/
pid_t wpid;
int status;
int ecode;
while((wpid = waitpid(-1,&status,WNOHANG)) != -1)
{
if(wpid > 0)
{
//子进程正常退出
if(WIFEXITED(status))
{
ecode = WEXITSTATUS(status);
printf("child wait success pid = %d ecode = %d\n",wpid,ecode);
}
else if(WIFSIGNALED(status))//信号杀死
{
ecode = WTERMSIG(status);
printf("child waip sig pid = %d ecode = %d\n",wpid,ecode);
}
}
}
while(1);
return 0;
}
GitHub链接
获取源码点击这里