当前位置: 首页 > 编程笔记 >

使用mmap实现多进程对大文件拷贝

柴磊
2023-03-14
本文向大家介绍使用mmap实现多进程对大文件拷贝,包括了使用mmap实现多进程对大文件拷贝的使用技巧和注意事项,需要的朋友参考一下

本文实例为大家分享了mmap实现文件多进程拷贝,供大家参考,具体内容如下

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

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

思路:

//1. 指定创建子进程的个数
//2. 打开源文件
//3. 打开目的文件, 不存在则创建
//4. 获取文件大小
//5. 根据文件大小拓展目标文件
//6. 为源文件创建映射
//7. 为目标文件创建映射
//8. 求出每个子进程该拷贝的字节数
//9. 创建N个子进程
//10. 子进程完成分块拷贝(注意最后一个子进程拷贝起始位置)
//11. 释放映射区

代码如下:

#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include<sys/wait.h>
#include<string.h>
#include <fcntl.h>
 
 
int main(int argc,char*argv[])
{
 int n;
 if(argc < 3 || argc > 4)
 {
 printf("Enter like this : ./a.out file_src file_dst [proc_number]\n");
 exit(1);
 }
 else if(argc == 3) //用户未指定,默认创建5个进程。
 n = 5;
 else
 n = atoi(argv[3]);
 
 //2.打开源文件
 int fd_src = open(argv[1],O_RDONLY);
 if(fd_src < 0)
 {
 perror("open");
 exit(2);
 }
 //3.打开目标文件,不存在就创建,存在则截断为0的大小。
 int fd_dst = open(argv[2],O_RDWR |O_CREAT |O_TRUNC,0664);
 if(fd_dst < 0)
 {
 perror("open");
 exit(3);
 }
 //4.获取源文件大小。
 struct stat sbuf;
 int ret = fstat(fd_src,&sbuf); //fd_src所指向的文件信息保存到结构体sbuf中。
 if(ret < 0)
 {
 perror("fstat");
 exit(4);
 }
 int flen = sbuf.st_size; //源文件大小。
 if(flen < n) //文件长度小于进程个数。
 {
 n = flen;
 }
 //5.根据文件大小拓展目标文件。
 ret = ftruncate(fd_dst,flen);//将参数fd指定的文件大小改为参数length指定的大小
 if(ret < 0)
 {
 perror("ftruncate");
 exit(5);
 }
 //6.为源文件创建映射。
// void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
//addr == NULL,表示内核选择一个合适的地址创建一个length大小的共享内存,
 char *mp_src = (char*)mmap(NULL,flen,PROT_READ,MAP_SHARED,fd_src,0); //0,表示将fd_src所指向的文件从起始映射到共享内存中,共享内存的权限为只读,进程间共享。
 if(mp_src == MAP_FAILED) //mmap一定要检查返回值。
 {
 perror("mmap");
 exit(6);
 }
 close(fd_src);
 
 //7.为目标文件创建映射。
 char *mp_dst = (char*)mmap(NULL,flen,PROT_READ|PROT_WRITE,MAP_SHARED,fd_dst,0);
 if(mp_dst == MAP_FAILED) //mmap一定要检查返回值。
 {
 perror("mmap");
 exit(7);
 }
 close(fd_dst);
 
 //8.求出每个进程拷贝的字节数。
 int bs = flen / n;
 int mod = flen % bs; //求出均分后余下的字节数,让最后一个子进程处理。
 
 char *temp_src = mp_src;
 char *temp_dst = mp_dst;
 
 //9.创建n个子进程。
 int i ;
 pid_t pid;
 for(i = 0; i < n; ++i)
 {
 printf("create %dth proc\n",i);
 if( (pid =fork()) == 0 )
  break;
 }
 if(n == i) //父进程。
 {
 int j = 0;
 for(j = 0; j < n; ++j)
  wait(NULL);
 }
 else if(i == (n-1)) //10.子进程拷贝,最后一个子进程,它多处理均分后剩下的字节数。
 {
 printf("i = %d\n",i);
 memcpy(temp_dst+i*bs,temp_src+i*bs,bs+mod);
 }
 else if(i == 0)
 {
 printf("i = %d\n",i);
 memcpy(temp_dst,temp_src,bs);
 }
 else 
 {
 printf("i = %d\n",i);
 memcpy(temp_dst+i*bs,temp_src+i*bs,bs);
 }
 
 //11.释放映射区。
 
 munmap(mp_src,flen);
 munmap(mp_dst,flen);
 
 return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 问题内容: 在Windows上的Python中,我可以通过创建一个大文件 现在大约是1 GB。但是,在Linux上,这将返回。 有没有办法在Linux上获得与Windows相同的行为?也就是说,能够使用?来增加文件的大小。 问题答案: 至少在POSIX系统上,不能用于增加(或减小)文件的大小。的功能是将文件的一部分映射到内存。合乎逻辑的是,您请求映射的东西应该确实存在!坦白说,我真的很惊讶您实际上

  • 本文向大家介绍linux下如何实现快速拷贝大文件,包括了linux下如何实现快速拷贝大文件的使用技巧和注意事项,需要的朋友参考一下 拷贝数据 远程拷贝数据的时候,我们一般使用rsync命令,但是如果拷贝大量的小文件,会导致rsync的传输速度慢。使用tar pv lz4打包压缩传输,可以解决这问题,使用这个方法,等同于使用scp、rsync传输大文件。 实测,使用rsync传输1200G,单个文件

  • 本文向大家介绍如何使用Python脚本实现文件拷贝,包括了如何使用Python脚本实现文件拷贝的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了如何使用Python脚本实现文件拷贝,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.实现目的 统一时间对服务器某文件夹内文件进行备份保存,如若备份成功则不提示任何错误,否则将以邮件的形式告知

  • 本文向大家介绍使用Bash Shell对目录中的文件实现递归式拷贝,包括了使用Bash Shell对目录中的文件实现递归式拷贝的使用技巧和注意事项,需要的朋友参考一下 前言     今天工作中遇到了一个问题,如果将目录A中的文件拷贝到目录B中(前提目录B没有该文件),并保持文件在目录A的结构。项目重点如下:     需要在目录B中保持文件在目录A中的结构。假设A目录文件 A/test/1.txt,

  • 问题内容: 我想在Linux机器正在使用的巨大页面上分配内存。我看到有两种方法可以使用和。 也就是说,在调用中使用标志- 和带有呼叫标志- 有人可以解释两者之间的区别吗? 问题答案: 这两个函数执行不同的操作,在您的上下文中这可能无关紧要: 为所有与传递给它的区域相对应的内存映射设置一个标志,告诉内核线程可以考虑将所述映射提升为大页面。只有启用了透明大页面支持(在下提供了透明大页面支持的状态),这

  • 本文向大家介绍java 实现文件夹的拷贝实例代码,包括了java 实现文件夹的拷贝实例代码的使用技巧和注意事项,需要的朋友参考一下 java 实现文件夹的拷贝实例代码         这里就直接上代码,废话不多说,很简单很实用。 实例代码: 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!