Linux--多进程拷贝一个文件

下面程序是一个精简版的多进程拷贝文件,要求源文件是一个文件,而不是一个目录。程序注意点是,必须在创建进程后在进程中打开源和目的文件,否则,

通过fork之后,多个进程会同时共享一个文件表项,导致读写文件混乱。由于每个进程分割地拷贝源文件的各个部分,所以不会出现写入文件混乱


#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <assert.h>
#include <sys/wait.h>

#define MAX_PATH 255
#define ONE_M (1024*1024)
#define LINE_SIZE 1024

int copy(const char *src, const char *dst, int processNum);
int multi_process_copy(const char *src, const char *dst, int processNum);
int copy_process(const char *src, const char *dst, int paceSize, int processNum, int srcFileSize);
int core_copy(int fdSrc, int fdDst, int posBegin, int posEnd, int srcFileSize, int flag);
const char *getRetValue(int retCode);

enum error_no
{
	ERROR_SUCCESS = 0,
	ERROR_INVALID_PARAMS = 1,
	ERROR_INVALID_PERMITS = 2,
	ERROR_INVALID_FILE_STAT = 3,
	ERROR_INVALID_DIR = 4,
	ERROR_FILE_CREATE = 5,
	ERROR_COPY_FAIL = 6,
	ERROR_OPEN_FILE = 7,
	ERROR_WAIT_CHILD_PROCESS = 8,
	ERROR_SEEK_FILE = 9,
	ERROR_WRITE_ERROR = 10
};

int main(int argc, char *argv[])
{
	if (argc != 4)
	{
		printf("usage: %s src dst process_num\n", argv[0]);
		return ERROR_INVALID_PARAMS;
	}
	
	char src[MAX_PATH] = {0};
	char dst[MAX_PATH] = {0};
	int processNum = 0;
	
	strncpy(src, argv[1], strlen(argv[1]));
	strncpy(dst, argv[2], strlen(argv[2]));
	processNum = (int)atoi(argv[3]);
	
	if (processNum < 0) //auto
	{
		processNum = 0;
	}
	
	int ret = copy(src, dst, processNum);
	printf("result: %s\n", getRetValue(ret));
}

int copy(const char *src, const char *dst, int processNum)
{
	assert(src != NULL);
	assert(dst != NULL);
	
	if (access(src, F_OK) < 0)
	{
		perror("access");
		return ERROR_INVALID_PERMITS;
	}
	
	struct stat fileInfo;
	
	if (stat(src, &fileInfo) < 0)
	{
		perror("stat");
		return ERROR_INVALID_FILE_STAT;
	}
	
	if (fileInfo.st_mode & S_IFDIR)
	{
		return ERROR_INVALID_DIR;
	}
	
	if (access(dst, F_OK) < 0)
	{
		int fd = open(dst, O_CREAT, 0755);
		if (!fd)
		{
			perror("create");
			return ERROR_FILE_CREATE;
		}
		close(fd);
	}
	else
	{
		int fd = open(dst, O_TRUNC);
		if (!fd)
		{
			perror("open");
			return ERROR_FILE_CREATE;
		}
		close(fd);
	}
	
	return multi_process_copy(src, dst, processNum);
}

int multi_process_copy(const char *src, const char *dst, int processNum)
{
	assert(src != NULL);
	assert(dst != NULL);
	
	struct stat fileInfo;
	if (stat(src, &fileInfo) < 0)
	{
		perror("stat");
		return ERROR_INVALID_FILE_STAT;
	}
	
	int srcFileSize = (int) fileInfo.st_size;
	int paceSize = 0;
	
	if (processNum == 0)
	{
		processNum = srcFileSize / ONE_M + 1;
		paceSize = ONE_M;
	}
	else
	{
		if (processNum > 1)
		{
			paceSize = srcFileSize / processNum + srcFileSize % processNum;
		}
		else
		{
			paceSize = srcFileSize;
		}
	}
	
	int retCode = 0;
	if ( ( retCode = copy_process(src, dst, paceSize, processNum, srcFileSize)) == ERROR_SUCCESS )
	{
		return ERROR_SUCCESS;
	}
	else
	{
		return ERROR_COPY_FAIL;
	}
}

int copy_process(const char *src, const char *dst, int paceSize, int processNum, int srcFileSize)
{
	assert(src != NULL);
	assert(dst != NULL);
	
	if (paceSize == 0)
	{
		return ERROR_SUCCESS;
	}
	
	if (srcFileSize > 0)
	{
		int fdDst = open(dst, O_WRONLY);
		if (!fdDst)
		{
			perror("open");
			return ERROR_OPEN_FILE;
		}
		
		lseek(fdDst, srcFileSize, SEEK_SET);
		write(fdDst, '\0', 1);
	}
	
	
	pid_t pid;
	int i = 0;
	for (; i < processNum; i++)
	{
		pid = fork();
		if (pid == 0)
		{
			break;
		}
	}
	
	if (pid == 0)
	{
		int fdSrc = open(src, O_RDONLY);
		if (!fdSrc)
		{
			perror("open");
			return ERROR_OPEN_FILE;
		}
		
		int fdDst = open(dst, O_WRONLY);
		if (!fdDst)
		{
			perror("open");
			return ERROR_OPEN_FILE;
		}
		
		int posBegin = i * paceSize;
		int posEnd = posBegin + paceSize;
		
		//printf("process[%d](%d--%d), total: %d\n", i, posBegin, posEnd, posEnd - posBegin);
		if ( posBegin <= srcFileSize && posEnd > srcFileSize )
		{
			return core_copy(fdSrc, fdDst, posBegin, posEnd, srcFileSize, 1);
		}
		else if ( posBegin <= srcFileSize && posEnd <= srcFileSize )
		{
			return core_copy(fdSrc, fdDst, posBegin, posEnd, srcFileSize, 0);
		}
		else
		{
			return ERROR_SUCCESS;
		}
	}
	else
	{
		int status;
		while(waitpid(-1, &status, 0) > 0)
		{
			if ( WIFEXITED(status) == 0 )
			{
				unlink(dst);
				return ERROR_COPY_FAIL;
			}
		}
	}
	
	return ERROR_SUCCESS;
}

int core_copy(int fdSrc, int fdDst, int posBegin, int posEnd, int srcFileSize, int flag)
{
	off_t size = 0;
		
	if (lseek(fdSrc, posBegin, SEEK_SET) < 0)
	{
		return ERROR_SEEK_FILE;
	}
	
	if (lseek(fdDst, posBegin, SEEK_SET) < 0)
	{
		return ERROR_SEEK_FILE;
	}
	
	int length = 0;
	if (flag)
	{
		length = srcFileSize - posBegin;
	}
	else
	{
		length = posEnd - posBegin;
	}
	
	char line[LINE_SIZE] = {0};
	do
	{
		if ( length >= LINE_SIZE )
		{
			//printf("1.length: %d\n", length);
			memset(line, 0, sizeof(line));
			if ((size = read(fdSrc, line, sizeof(line)))> 0)
			{
				if ( write(fdDst, line, size) != size )
				{
					return ERROR_WRITE_ERROR;
				}
			}
			length -= LINE_SIZE;
		}
		else
		{
			//printf("2.length: %d\n", length);
			memset(line, 0, sizeof(line));
			if ((size = read(fdSrc, line, length))> 0)
			{
				if ( write(fdDst, line, size) != size )
				{
					return ERROR_WRITE_ERROR;
				}
				break;
			}
			break;
		}
	}while(1);
	
	return ERROR_SUCCESS;
}

const char *getRetValue(int retCode)
{
	switch(retCode)
	{
		case ERROR_SUCCESS:
			return "copy complete!!!";
			break;
		case ERROR_INVALID_PARAMS:
			return "invalid params";
			break;
		case ERROR_INVALID_FILE_STAT:
			return "cannot stat the file";
			break;
		case ERROR_INVALID_DIR:
			return "the src file cannot be directory";
			break;
		case ERROR_FILE_CREATE:
			return "error in creating the dest file";
			break;
		case ERROR_COPY_FAIL:
			return "copy file error";
			break;
		case ERROR_OPEN_FILE:
			return "open file error";
			break;
		case ERROR_WAIT_CHILD_PROCESS:
			return "cannot get the child status";
			break;
		case ERROR_SEEK_FILE:
			return "cannot seek this file, maybe not regular file";
			break;
		case ERROR_WRITE_ERROR:
			return "cannot write the dst file";
			break;
	}
}


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值