Linux下管道传递文件名后open函数调用失败的问题求解
问题分析与解决方法
核心问题
- 输入包含无效字符且未正确截断:父进程用
read读取用户输入时,会把回车键对应的\n读入缓冲区,还直接将整个20字节缓冲区写入管道,导致子进程收到的字符串里既有\n,还有缓冲区未被覆盖的随机垃圾数据,open无法识别正确文件名。 - 未传递有效字符串长度:父进程固定写入20字节,而非实际读取到的有效字符数,子进程无法准确定位文件名的结束位置。
修复步骤
1. 父进程处理输入并写入有效数据
读取输入后,先把\n替换为字符串终止符\0,再只写入实际的文件名长度(包含\0),而非整个缓冲区:
// 父进程部分修改 read(STDIN_FILENO, buf,20); // 定位换行符并替换为终止符 char *newline = strchr(buf, '\n'); if (newline != NULL) { *newline = '\0'; } // 仅写入有效字符串(含终止符) write(fp[1], buf, strlen(buf) + 1);
注意:需要新增<string.h>头文件,因为用到了strchr和strlen函数。
2. 子进程修正资源释放顺序
子进程里的管道关闭操作要放在exit之前,避免资源泄漏:
// 子进程部分修改 close(fp[1]); int fd; read(fp[0], buf,20); if((fd = open(buf, O_RDONLY)) == -1) { close(fp[0]); // 先关闭管道再退出 exit(1); } close(fp[0]); exit(0);
完整修复代码
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <sys/syscall.h> #include <sys/types.h> #include <sys/wait.h> #include <fcntl.h> #include <string.h> // 新增头文件 int main(){ int fp[2]; if (pipe(fp) < 0){ printf("error creating pipe\n"); exit(-1); } int id; char buf[20]; id=fork(); // 父进程部分 if (id!=0){ close(fp[0]); printf("program name: "); fflush(stdout); read(STDIN_FILENO,buf,20); // 处理换行符 char *newline = strchr(buf, '\n'); if (newline != NULL) { *newline = '\0'; } // 写入有效文件名 write(fp[1], buf, strlen(buf) + 1); int waitstatus, exitcode; wait(&waitstatus); if (WIFEXITED(waitstatus)) exitcode = WEXITSTATUS(waitstatus); else { printf("Bad exit\n"); return 0; } if (exitcode==1) printf("error, file doesn't exist\n"); else printf("file does exist\n"); close(fp[1]); } // 子进程部分 else{ close(fp[1]); int fd; read(fp[0],buf,20); if((fd = open(buf, O_RDONLY)) == -1) { close(fp[0]); exit(1); } close(fp[0]); exit(0); } }
补充说明
如果之前替换\n为\0后仍无效,大概率是因为父进程依旧写入了整个20字节缓冲区,导致\0后面的垃圾数据干扰了open的识别。上述方案通过只传递有效字符串,从根源避免了这个问题。
内容的提问来源于stack exchange,提问作者Maridiama
相关产品推荐
相关产品推荐

