首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >无法从管道读取,和另一个stdin问题。

无法从管道读取,和另一个stdin问题。
EN

Stack Overflow用户
提问于 2021-05-12 12:06:20
回答 2查看 325关注 0票数 1

所以,我刚才在这里问过,但这个问题有一半是因为我太笨了。但我还是有问题。我希望这比以前的问题更清楚。

我正在编写POSIX cat,我几乎可以使用它,但我有两个问题:

  1. 我的cat不能从管道中读取,我真的不知道为什么(重定向(<)工作正常)

  1. 我想不出如何使它连续阅读stdin,而没有一些问题。我有一个“很好”的版本,但是会产生堆栈溢出。如果只有stdin,则另一个版本不会停止从stdin读取,即:my-cat < file将从stdin读取,直到它被终止,但它必须从stdin读取,如果没有任何文件,它必须等待终止。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    char opt;
    while ((opt = getopt(argc, argv, "u")) != EOF) {
        switch(opt) {
            case 'u':
                /* Make the output un-buffered */
                setbuf(stdout, NULL);
                break;
            default:
                break;
        }
    }

    argc -= optind;
    argv += optind;

    int i = 0, fildes, fs = 0;

    do {
        /* Check for operands, if none or operand = "-". Read from stdin */
        if (argc == 0 || !strcmp(argv[i], "-")) {
            fildes = STDIN_FILENO;
        } else {
            fildes = open(argv[i], O_RDONLY);
        }

        /* Check for directories */
        struct stat fb;
        if (!fstat(fildes, &fb) && S_ISDIR(fb.st_mode)) {
            fprintf(stderr, "pcat: %s: Is a directory\n", argv[i]);
            i++;
            continue;
        }

        /* Get file size */
        fs = fb.st_size;

        /* If bytes are read, write them to stdout */
        char *buf = malloc(fs * sizeof(char));
        while ((read(fildes, buf, fs)) > 0)
            write(STDOUT_FILENO, buf, fs);

        free(buf);

        /* Close file if it's not stdin */
        if (fildes != STDIN_FILENO)
            close(fildes);

        i++;
    } while (i < argc);

    return 0;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-05-12 12:18:56

管道没有尺寸,终端也没有。对于此类文件,st_size字段的内容未定义。(在我的系统中,它似乎总是包含0,但我不认为有任何跨平台的保证。)

因此,您一次读取整个文件并再次将其全部写入的计划对于非常规文件是不可行的,甚至对它们也是有风险的(读取不能保证返回所请求的全部字节数)。如果文件很大,也会占用不必要的内存。

一个更好的策略是读入一个固定大小的缓冲区,并且只写出成功读取的字节数。重复此操作,直到到达文件结束为止,这由返回0的read()指示.这就是你解决第二个问题的方法。

同样地,write()也不能保证写出您要求它的全部字节数,所以您需要检查它的返回值,如果它很短,请再次尝试写出其余的字节。

下面是一个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define BUFSIZE 65536  // arbitrary choice, can be tuned for performance

ssize_t nread;
char buf[BUFSIZE]; // or char *buf = malloc(BUFSIZE);
while ((nread = read(filedes, buf, BUFSIZE)) > 0) {
    ssize_t written = 0;
    while (written < nread) {
        ssize_t ret = write(STDOUT_FILENO, buf + written, nread - written);
        if (ret <= 0)
            // handle error
        written += ret;
    }
}
if (nread < 0)
    // handle error

最后,您的程序通常缺少错误检查;例如,如果文件无法打开,它将继续执行filedes == -1操作。检查您发出的每个系统调用的返回值并相应地处理错误是非常重要的。这对于一个程序在现实生活中的使用是非常重要的,甚至对于作为练习而创建的玩具程序来说,它也将对调试它们非常有帮助。(例如,错误检查可能会给您提供一些线索,帮助您找出该程序的错误所在。)

票数 1
EN

Stack Overflow用户

发布于 2021-05-14 15:04:39

您的cat (您可以称它为my-cat,但我更愿意称它为felix,请允许我使用双关语)应该一直与stdio一起使用,以获得stdio包所做的缓冲的好处。下面是使用独占cat包(在K&R中几乎完全相同)的简化stdio版本,您将看到这是完全有效的,如所示(您将看到该结构与您的结构几乎完全相同,但我简化了数据副本/like K&R book/的处理,参数/yours的处理有点混乱/):

felix.c

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>

#define ERR(_code, _fmt, ...) do {            \
        fprintf(stderr,"%s: " _fmt, progname, \
                ##__VA_ARGS__);               \
        if (_code) exit(_code);               \
    } while (0)

char *progname = "cat";

void process(FILE *f);

int main(int argc, char **argv)
{
    int opt;
    while ((opt = getopt(argc, argv, "u")) != EOF) {
        switch (opt) {
        case 'u': setbuf(stdout, NULL); break;
        }
    }

    /* for the case it has been renamed, calculate the basename
     * of argv[0] (progname is used in the macro ERR above) */
    progname = strrchr(argv[0], '/');
    progname = progname
             ? progname + 1
             : argv[0];

    /* shift options */
    argc -= optind;
    argv += optind;

    if (argc) {
        int i;
        for (i = 0; i < argc; i++) {
            FILE *f = fopen(argv[i], "r");
            if (!f) {
                ERR(EXIT_FAILURE,
                    "%s: %s (errno = %d)\n",
                    argv[i], strerror(errno), errno);
            }
            process(f);
            fclose(f);
        }
    } else {
        process(stdin);
    }
    exit(EXIT_SUCCESS);
}

/* you don't need to complicate here, fgetc and putchar use buffering as you stated in main
 * (no output buffering if you do the setbuf(NULL) and input buffering all the time).  The buffer
 * size is best to leave stdio to calculate it, as it queries the filesystem to get the best
 * input/output size and create buffers this size. and the processing is simple with a loop like
 * the one below. You'll get no appreciable difference between this and any other input/output.
 * you can believe me, I've tested it. */
void process(FILE *f)
{
    int c;
    while ((c = fgetc(f)) != EOF) {
        putchar(c);
    }
}

正如您所看到的,没有为支持重定向做过什么特别的工作,因为重定向不是在程序中完成的,而是由调用它的程序完成的(在本例中是由shell完成的),当您启动一个程序时,您会收到三个已经打开的文件描述符。这些是shell正在使用的,或者shell在启动程序之前将其放置在0、1和2的位置。所以你的程序与重定向没有任何关系。一切都是在壳里完成的.这就是为什么您的程序重定向工作的原因,即使您没有为其工作做任何事情。如果要调用程序的输入、输出或重定向的标准错误(这不是从父进程接收到的标准输入、输出或错误),则只需进行重定向。但这不是我的猫的情况。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67510345

复制
相关文章
opencv无法读取图片_opencv无法读取图片
使用一下代码读取一张图片失败(不管是绝对路径还是相对路径,都失败),工程运行都没问题,就是图片读取失败。
全栈程序员站长
2022/11/04
2.4K0
Mac下IDE无法读取环境变量问题
今天遇到一个问题,Idea无法读取~/.bash_profile下的配置文件。 上网查了好久,都说是launchctl的问题。 但是其实我这边是因为安装了zsh,导致环境标量失效。 在~/.zshrc中添加: source ~/.bash_profile 然后执行,source ~/.zhshrc即可。
用户1154259
2018/03/28
2.5K0
C语言缓冲区之 gets(str);fflush(stdin); rewind(stdin);setbuf(stdin, NULL);
清空键盘缓冲区很多种方法,如用fflush(stdin); rewind(stdin);setbuf(stdin, NULL);前两者仅对windows有用,最后一个则对Linux系统也适用。那么为什么需要清空键盘缓冲区呢? 以下几个实例:
瑞新
2020/07/07
2.8K0
Mac无法读取硬盘
问题描述: 由于没有弹出移动硬盘,就拔出来了。导致再插入硬盘,电脑也无法识别了。 步骤: 1.查看一下硬盘信息 画圈的就是我的硬盘。 2.将这个硬盘挂载 sudo diskutil mount /dev/disk2s1 然后需要输入的就是你的密码(开机密码) 可以看到,已经挂载成功了。
用户4793865
2023/01/12
1.1K0
stdin and stdout which it's ?
最近写了几个C函数,来处理项目中一个Desktop跨应用的进程通信,被32-bit,LE(BE)折磨了很久,stdin and stdout 看起来是一个很简单的标准输入输出,但是处理的过程中,却遇到了很大的障碍,因为历史问题,一个bytes的长度,需要将消息的位置移动4个byte存储消息的长度,先发送给对方,告诉对方我即将发送一个多少长度的byte,反之解析也是亦然。
icepy
2019/06/24
9890
stdin and stdout which it's ?
进程通信(一)无名管道和有名管道
《王道考研复习指导》 管道通信是消息传递的一种特殊方式。所谓“管道”,是指用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又名pipe文件。向管道(共享文件)提供输入的发送进程(即写进程),以字符流的形式将大量的数据送入(写)管道;而接受管道输出的接受进程(即读进程),则从管道接受(读)数据。为了协调双方的通信,管道机制必须提供一下三个方面的协调能力:互斥、同步和确定对方存在。 下面以linux的管道为例进行说明。在linux中,管道是一种频繁使用的通信机制。从本质上讲,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件通信的两个问题,具体表现为: 1)限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为4KB,使得它不像文件那样不加检验的增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对写管道的write()调用将默认的阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。 2)读进程也可能工作的比写进程快。当所有当前进程数据已被读走时,管道变空。当这种情况发生时,一个随后的read()调用将默认设置为阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。 注意 :从管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以便写更多的数据。管道只能采用半双工通信,即在某一时刻只能单向传输。要实现父子进程双方互动,需要定义两个管道。
lexingsen
2022/02/24
1.6K0
进程通信(一)无名管道和有名管道
pyspark之从HDFS上读取文件、从本地读取文件
hdfs上的路径: path="hdfs:///主机名:端口号/地址" 本地上的路径: path"file:///本地地址" 读取文件: rdd=sc.textFile(path)
西西嘛呦
2020/08/26
5.1K0
相机SD卡无法读取提示格式化 相机SD卡无法读取怎么修复
相机SD卡中储存着的照片和视频,承载着我们美好的回忆。因为相机SD卡的容量有限,我们会定期对SD卡中的数据进行云盘备份,然后清理相机SD卡中的数据。在打开相机SD卡时,可能会遇到SD卡无法读取的情况。那么,相机SD卡无法读取提示格式化,相机SD卡无法读取怎么修复?今天作者就和大家介绍一下这两个问题。
用户9208731
2023/04/18
4.2K1
相机SD卡无法读取提示格式化 相机SD卡无法读取怎么修复
【从零学习OpenCV】保存和读取XML和YMAL文件
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《从零学习OpenCV 4》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。
小白学视觉
2019/11/15
2.7K0
【从零学习OpenCV】保存和读取XML和YMAL文件
【错误记录】Android 应用连接 BLE 设备无法读取数据 ( 可以写出数据 | 无法读取数据 )
发送数据成功 : Android 应用 向 BLE 硬件设备发送数据 , 成功 ;
韩曙亮
2023/03/28
1.5K0
Linux gzip: stdin: not in gzip format
在解压tar.gz文件的时候报错 tar -zxvf otp_src_18.3.tar.gz gzip: stdin: not in gzip format tar: Child returned
Arebirth
2020/06/19
3.1K0
Linux基础之cd无法进入xargs管道输出的目录问题解决方法
今天在利用jenkins将项目部署到远程服务器,里面有个步骤涉及到切换目录,执行部署脚本的命令,原本思路是利用xargs和cd配合进行目录切换,执行的shell命令如下
lyb-geek
2018/12/25
2.7K0
shell 管道与重定向
使用 >> 或 > 将输出流重定向到文件。如果文件不存在则创建文件;如果文件已存在的话,> 覆盖文件,>> 附加文本到文件。例如:
sir5kong
2023/05/25
8570
解决 Grep 的多次管道过滤问题
在日常的开发过程中,我们利用grep可以方便快捷的查找感兴趣的日志内容,极大地提升了开发和排错效率。但是有时候,我们也会遇到一些问题,比如。
技术小黑屋
2020/01/21
1.7K0
如何从 Ring Buffer 读取?
原文地址:http://mechanitis.blogspot.com/2011/06/dissecting-disruptor-how-do-i-read-from.html​​ 作者是 Trisha Gee, LMAX 公司的一位女工程师。 这是理解 LMAX​ 开发的 Disruptor 模式​ 系列博客的下一篇。 从 上一篇博客​ 我们都明白了什么是 Ring Buffer 以及 它有多棒。遗憾的是,我还没有提到当你实际使用 Disruptor 时,怎样读写数据。 ConsumerBarrier 与
张善友
2018/01/29
2K0
如何从 Ring Buffer 读取?
LinuxShell重定向和管道
Linux Shell 提供重定向符用于重定向命令的输入和输出,提供管道符用于将一个命令的输出重定向作为另一个命令的输入。
hotarugali
2022/02/28
9480
Spring4.0+Mybatis整合时占位符无法读取jdbc.properties的问题
1、在使用Spring+Mybatis整合时遇到了一个问题,在bean.xml配置文件引用外部jdbc.properties的时候报错,如下所示:
别先生
2021/03/04
2.1K0
logstash之input配置stdin类型详解
配置示例 input { stdin { type => "demo-stdin" add_field => {"test" => "hello"} codec => "plain" tags => ["stdin-test"] } } output { stdout{ codec=>rubydebug } } 启动 bin/logstash -f /etc/logstash/conf.d/demo-input-stdin.conf 输入test 返回 { "
苦咖啡
2018/04/28
8370
点击加载更多

相似问题

使用管道从STDIN读取分叉过程的问题

11

无法从STDIN正确读取

31

Python同时从管道进程和Popen子进程读取stdin

119

如何从STDIN或Unix管道中读取流

12

PHP :使用管道时如何从键盘STDIN读取?

13
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文