欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux——实现文件的多进程拷贝

程序员文章站 2024-03-19 18:57:46
...

                                                                       需求:实现文件多进程拷贝

假设有一个超大文件,需对其完成拷贝工作。为提高效率,可采用多进程并行拷贝的方法来实现。假设文件大小为len,共有n个进程对该文件进行拷贝。那每个进程拷贝的字节数应为len/n。但未必一定能整除,我们可以选择让最后一个进程负责剩余部分拷贝工作。可使用len % (len/n)将剩余部分大小求出。

为降低实现复杂度,可选用mmap来实现源、目标文件的映射,通过指针操作内存地址,设置每个进程拷贝的起始、结束位置。借助MAP_SHARED选项将内存中所做的修改反映到物理磁盘上。

Linux——实现文件的多进程拷贝

 实现源代码如下:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>

void err_int(int ret, const char *err)
{
    if (ret == -1) {
        perror(err);
        exit(1);
    }

    return ;
}

void err_str(char *ret, const char *err)
{
    if (ret == MAP_FAILED) {
        perror(err);
        exit(1);
    }
}

int main(int argc, char *argv[])
{   
    int fd_src, fd_dst, ret, len, i, n;
    char *mp_src, *mp_dst, *tmp_srcp, *tmp_dstp;
    pid_t pid;
    struct stat sbuf;

    if (argc < 3 || argc > 4) {
        printf("Enter like this please: ./a.out file_src file_dst [process number]\n");
        exit(1);
    } else if (argc == 3) {
        n = 5;                  //用户未指定,默认创建5个子进程
    } else if (argc == 4) {
        n = atoi(argv[3]);
    }

    //打开源文件
    fd_src = open(argv[1], O_RDONLY);
    err_int(fd_src, "open dict.txt err");
    //打开目的文件, 不存在则创建
    fd_dst = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0664);
    err_int(fd_dst, "open dict.cp err");
    //获取文件大小
    ret = fstat(fd_src, &sbuf);
    err_int(ret, "fstat err");
    
    len = sbuf.st_size;
    if (len < n)                //文件长度小于进程个数
        n = len;
    //根据文件大小拓展目标文件
    ret = ftruncate(fd_dst, len);
    err_int(ret, "truncate fd_dst err");
    //为源文件创建映射
    mp_src = (char *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd_src, 0);
    err_str(mp_src, "mmap src err");
    //为目标文件创建映射
    mp_dst = (char *)mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_dst, 0);
    err_str(mp_dst, "mmap dst err");

    tmp_dstp = mp_dst;
    tmp_srcp = mp_src;
    //求出每个子进程该拷贝的字节数
    int bs = len / n;    //每个子进程应该拷贝的字节数
    int mod = len % bs;  //求出均分后余下的字节数,让最后一个子进程处理

    //创建N个子进程
    for (i = 0; i < n; i++) {
        if ((pid = fork()) == 0) {
            break;
        }
    }

    if (n == i) {               //父进程
        for (i = 0; i < n; i++)
            wait(NULL);

    } else if (i == (n-1)){     //最后一个子进程,它多处理均分后剩余几个字节
        memcpy(tmp_dstp+i*bs, tmp_srcp+i*bs, bs+mod); 
    } else if (i == 0) {        //第一个子进程
        memcpy(tmp_dstp, tmp_srcp, bs); 
    } else {                    //其他子进程
        memcpy(tmp_dstp+i*bs, tmp_srcp+i*bs, bs); 
    }

    munmap(mp_src, len);
    munmap(mp_dst, len);

    return 0;
}

 

相关标签: 多进程