大文件拷贝
假设有一个超大文件,需对其完成拷贝工作。为提高效率,可采用多进程并行拷贝的方法来实现。假设文件 大小为 len,共有 n 个进程对该文件进行拷贝。那每个进程拷贝的字节数应为 len/n。但未必一定能整除,我们可 以选择让最后一个进程负责剩余部分拷贝工作。可使用 len%(len/n)将剩余部分大小求出。
为降低实现复杂度,可选用 mmap 来实现源、目标文件的映射,通过指针操作内存地址,设置每个进程拷贝 的起始、结束位置。借助 MAP_SHARED 选项将内存中所做的修改反映到物理磁盘上
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
int main(int argc,char *argv[])
{
int n=5;
//输入参数至少是3,第四个参数可以是进程个数
if(argc<3){
printf("./a.out src dst [n]\n");
return 0;
}
if(argc==4){
n=atoi(argv[3]);
}
//打开源文件
int srcfd=open(argv[1],O_RDONLY);
if(srcfd<0){
perror("open err");
exit(1);
}
//打开目标文件
int dstfd=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0644);
if(dstfd<0){
perror("open dst err");
exit(1);
}
//目标拓展,从原文件获得文件大小,stat
struct stat sb;
stat(argv[1],&sb);//为了计算大小
int len=sb.st_size;
truncate(argv[0],len);
//将源文件映射到缓冲区
char *psrc = mmap(NULL,len,PROT_READ,MAP_SHARED,srcfd,0);
if(psrc == MAP_FAILED){
perror("mmap dst err");
exit(1);
}
//将目标文件映射
char *pdst = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,dstfd,0);
if(pdst == MAP_FAILED){
perror("mmap dst err");
exit(1);
}
//创建多个子进程
int i=0;
for(i=0;i<n;i++)
{
if(fork()==0)
break;
}
//计算子进程需要拷贝的起点和大小
int cpsize=len/n;
int mod=len%n;
//数据拷贝 ,memcpy
if(i<n){ //子进程
if(i== n-1){ //最后一个子进程
memcpy(pdst+i*cpsize,psrc+i*cpsize,cpsize+mod);
}
else{
memcpy(pdst+i*cpsize,psrc+i*cpsize,cpsize);
}
}
else{
for(i=0;i<n;i++)
{
wait(NULL);
}
}
//释放映射区
if(munmap(psrc,len)<0){
perror("munmao src err");
exit(1);
}
//关闭文件
close(srcfd);
close(dstfd);
return 0;
}