#include <head.h>
// 父子进程在宏观上同时执行,微观上实际是时间片轮询串行。
//两个进程同时调用同一个拷贝函数进行拷贝
int get_file_len(const char *src){
// 每个文件进程控制块中都有一份文件描述符表
// (可以把它看成是一个数组,里面的元素是指向file结构体指针类型),
// 这个数组的下标就是文件描述符。
// 在源代码中,一般用fd作为文件描述符的标识。
int fd,len;
if((fd = open(src,O_RDONLY))==-1)
PRINT_ERR("open src error");
len = lseek(fd,0,SEEK_END);
//将光标定位到最后,返回总字节数给len
//这时光标在结尾,所以要关闭文件
close(fd);
return len;
}
int init_dest_file(const char *dest){
//初始化目标文件,保证拷贝文件时目标文件是存在的
//有则清空写入,无则创建给读写权限
int fd;
if((fd = open(dest,O_WRONLY|O_TRUNC|O_CREAT,0666))==-1)
PRINT_ERR("open dest error");
close(fd);
return 0;
}
int copy_file(const char *src,const char *dest,int start, int len){
int fd1,fd2,ret,count=0;
char buf[128]={0};
//如果是先打开文件,在fork进程此时2个进程同时用一个光标
//而如果先fork在打开是2个进程分别打开他们对应各自的文件,
//2个进程用他们各自的光标,这个函数分别被2个进程同时调用
//打开两个文件
if((fd1 = open(src,O_RDONLY))==-1)
PRINT_ERR("open src error");
if((fd2 = open(dest,O_WRONLY))==-1)
PRINT_ERR("open dest error");
//定位2个进程的光标要拷贝的开始位置
lseek(fd1,start,SEEK_SET);
lseek(fd2,start,SEEK_SET);
//循环拷贝
while(1){
//先读fd1的数据到字符串内
ret = read(fd1,buf,sizeof(buf));
count+=ret;//记录拷贝的字节数
//再将字符串的内容写入fd2中
//如果字符串读取字符数量不满128执行下面
//判断buf是否读满
//当子进程先复制时,复制的是前半部分,最后一次ret读取的是128,count是128的倍数
//这样读取最后一次会超过len/2的位置,而我们值想要len/2之前的字符串
if(count >= len){
write(fd2, buf, ret-(count-len));
break;//循环停止的条件count >= len
}
//如果字符串满拷贝执行下面
write(fd2,buf,ret);
}
}
// ./a.out srcfile destfile
int main(int argc, const char *argv[])
{
int len = 0;
pid_t pid;
//检查参数
if(argc != 3){
fprintf(stderr,"input error,try again\n");
fprintf(stderr,"usage:./a.out srcfile destfile\n");
return -1;
}
//获取文件的大小,为了做光标定位,父进程定位1/2长度位置
len = get_file_len(argv[1]);
//初始化目标文件,保证拷贝文件时目标文件是存在的
//有则清空写入,无则创建给读写权限
init_dest_file(argv[2]);
//fork进程
pid = fork();//每fork一次就创建一个进程
//pid_t就是一个short类型变量,pid就是一个short的数字而已,
// 实际表示的是内核中的进程表的索引。
//先把进程if框架写出
if(pid == -1){//-1为创建失败
PRINT_ERR("fork error");//有置位,报错显示
}else if(pid == 0){//pid为0时 此时为子进程操作
//子进程光标 从0开始拷贝移动 len/2的长度
copy_file(argv[1],argv[2],0,len/2);
}else{//pid为其他值时为父进程操作,此时pid是子进程的值
//当fork后会有2个进程同时在运行这一套程序,
//满足pid为0的说明是子进程在运行这个程序
//满足pid为其他值的说明是父进程在运行这个程序
//父进程光标 从len/2开始拷贝移动 len-len/2的长度
copy_file(argv[1],argv[2],len/2,len-len/2);
wait(NULL);
//父进程直到子进程运行结束后回收子进程,防止孤儿进程
}
return 0;
}