目录
题目
通过两个进程实现cp功能
思路分析
一、整体功能概述
这段代码通过两个进程(分别由
input.c
和output.c
编译生成的可执行文件代表)以及一个有名管道(fifo
)来实现类似于cp
(复制文件)的功能。一个进程负责从源文件读取数据并写入有名管道,另一个进程从有名管道读取数据并写入目标文件。二、
input.c
分析
命令行参数处理:
- 检查传入的参数数量是否正确。这里期望有两个参数,第一个是程序名本身,第二个是源文件名。
有名管道创建与处理:
- 使用
mkfifo
函数创建有名管道,如果管道已经存在(errno == EEXIST
),则输出提示信息。- 若创建管道过程中出现其他错误,通过
perror
输出错误信息并返回-1
。文件打开:
- 打开有名管道用于写入数据(
O_WRONLY
)。- 打开源文件用于读取数据(
O_RDONLY
)。- 如果打开文件失败,通过
perror
输出错误信息并返回-1
。数据复制循环:
- 在一个无限循环中,从源文件读取数据到
buf
中,每次最多读取 32 个字节(read(fd_file, buf, 32)
)。- 如果读取到的字节数为 0,表示源文件已读完,退出循环。
- 将读取到的数据写入有名管道(
write(fd_fifo, buf, s)
)。资源关闭:
- 关闭有名管道和源文件的文件描述符。
三、
output.c
分析
命令行参数处理、有名管道创建与处理、文件打开:
- 与
input.c
中的这些部分类似,处理命令行参数、创建有名管道(如果已存在则输出提示信息)以及打开有名管道(用于读取数据)和目标文件(用于写入数据,并使用O_WRONLY | O_CREAT | O_TRUNC
标志确保可写、创建新文件或截断已有文件)。数据复制循环:
- 同样在一个无限循环中,从有名管道读取数据到
buf
中,每次最多读取 32 个字节(read(fd_fifo, buf, 32)
)。- 如果读取到的字节数为 0,表示有名管道中已无数据可读,退出循环。
- 将读取到的数据写入目标文件(
write(fd_file, buf, s)
)。资源关闭:
- 与
input.c
类似,关闭有名管道和目标文件的文件描述符。四、总体执行流程分析
- 分别编译
input.c
和output.c
生成可执行文件(假设为input
和output
)。- 在命令行中分别运行这两个程序,传入源文件和目标文件的路径作为参数。
input
程序创建有名管道,打开源文件和有名管道,然后从源文件读取数据并写入有名管道。output
程序也创建有名管道(如果已存在则识别到),打开目标文件和有名管道,然后从有名管道读取数据并写入目标文件。- 两个程序通过有名管道进行数据传输,实现了类似于
cp
命令的文件复制功能。五、应用场景和注意事项
应用场景:
- 可以用于在不同的进程之间进行文件数据的传输,特别是在需要将数据从一个程序传递到另一个程序进行处理的场景中。
- 适用于实现一些分布式或并行处理的系统中,不同的进程负责不同的任务,通过有名管道进行数据交互。
注意事项:
- 确保有名管道的名称在系统中是唯一的,以避免与其他程序的冲突。
- 考虑在使用完毕后及时删除有名管道,以避免占用系统资源。
- 注意处理可能出现的文件打开错误、管道创建错误等异常情况,确保程序的稳定性和可靠性。
input.c
input.c 读源文件//创建有名管道
//打开管道文件和源文件
//循环读源文件,写入管道
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
int fd_fifo, fd_file;
char buf[32] = "";
ssize_t s;
if (mkfifo("fifo", 0666) < 0)
{
if (errno == EEXIST)
printf("file exist!\n");
else
{
perror("mkfifo err");
return -1;
}
}
printf("mkfifo success!\n");
//打开文件
fd_fifo = open("fifo", O_WRONLY);
fd_file = open(argv[1], O_RDONLY);
if (fd_fifo < 0)
{
perror("open err");
return -1;
}
if (fd_file < 0)
{
perror("open err");
return -1;
}
//读源文件,写入管道
while (1)
{
s = read(fd_file,buf,32); //从文件读到buf中
if(s == 0)
break;
write(fd_fifo,buf,s); //把buf中数据写进有名管道
}
close(fd_fifo);
close(fd_file);
return 0;
}
out.c
ouput.c 写目标文件//创建有名管道
//打开管道文件和目标文件
//循环读管道,写入目标文件
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, char const *argv[])
{
int fd_fifo, fd_file;
char buf[32] = "";
ssize_t s;
if (mkfifo("fifo", 0666) < 0)
{
if (errno == EEXIST)
printf("file exist!\n");
else
{
perror("mkfifo err");
return -1;
}
}
printf("mkfifo success!\n");
//打开文件
fd_fifo = open("fifo", O_RDONLY);
fd_file = open(argv[1], O_WRONLY | O_CREAT |O_TRUNC,0666);
if (fd_fifo < 0)
{
perror("open err");
return -1;
}
if (fd_file < 0)
{
perror("open err");
return -1;
}
//读管道,写入目标文件
while (1)
{
s = read(fd_fifo,buf,32); //从有名管道中读数据到buf
if(s == 0)
break;
write(fd_file,buf,s); //把buf中数据写到
}
close(fd_fifo);
close(fd_file);
return 0;
}