程序在尝试使用 read() 系统调用读取文件时卡住

Program gets stuck while trying to read a file using read() system call

这是我的代码片段:

int fd;
bufsize = 30;
char buf[bufsize];
char cmd[100] = "file.txt";
int newfd = 1;

if (fd = open(cmd,O_RDONLY) >=0){
    puts("wanna read");
    while (read(fd,&bin_buf,bufsize)==1){
        puts("reading");
        write(newfd,&bin_buf,bufsize);
    }
    close(fd);
}

所以这里程序打印 "wanna read" 但从不打印 "reading"。我也试过使用非阻塞标志打开,但没有用。有谁能够帮助我?我必须只使用 open()read() 系统调用。谢谢。 编辑:我在代码中做了一些澄清。实际上,我正在写入的 newfd 是一个套接字描述符,但我认为这对这个问题并不重要,因为它停留在 write.[=17= 之前的 read 上]

read returns 从文件读取的字节数可以是 bufsize 或更少,如果必须读取的文件的剩余部分短于 bufsize.

在您的情况下,很可能 bufsize 大于 1 并且文件大于 1 字节,因此 while 循环的条件被评估为 false,代码被跳到文件关闭的位置。

你应该检查是否有更多字节要读取:

while( read(fd,&bin_buf,bufsize) > 0 ) {

第一个问题是你的if语句。您忘记使用足够的括号,所以如果 open() 有效,则读取会尝试从文件描述符 1 读取,也就是标准 output。如果那是你在 Unix 机器上的终端(可能是),那么它就可以工作——尽管这可能令人惊讶;该程序正在等待您输入内容。

修复:使用括号!

if ((fd = open(cmd, O_RDONLY)) >= 0)

赋值是在比较之前而不是之后完成的。

我顺便观察到你没有显示你是如何设置 cmd 的,但是如果你看到 'wanna read' 消息,那一定没问题。您没有显示 newfd 是如何初始化的;也许那也是 1

您也遇到了 'what the read() call returns' 的问题。您可能需要:

int fd;
char buf[bufsize];
int newfd = 1;

if ((fd = open(cmd, O_RDONLY)) >= 0)
{
    puts("wanna read");
    int nbytes;   // ssize_t if you prefer
    while ((nbytes = read(fd, buf, sizeof(buf))) > 0)
    {
        puts("reading");
        write(newfd, buf, nbytes);
    }
    close(fd);
}

你可以用你原来的if但我的循环体输入一些东西('Surprise',或'Terminal file descriptors are often readable and writable'或其他东西)然后写在某个地方来证明我的主要观察。

您的 read() 调用尝试读取 bufsize 字节和 returns 实际读取的字节数。除非 bufsize ==read() 不太可能 return 1,因此该块几乎总是被跳过,什么也不会写入。

还要注意 if (fd = open(cmd, O_RDONLY) >= 0) 是不正确的,如果文件存在,会将 fd 设置为 1,标准输出的句柄,导致 read 失败因为标准输入很可能没有打开阅读。

请注意,使用 read 系统调用进行读取在某些环境下会很棘手,因为 return 值 -1 可能会重新启动。

这是一个改进的版本:

int catenate_file(const char *cmd, int newfd, size_t bufsize) {
    int fd;
    char buf[bufsize];

    if ((fd = open(cmd, O_RDONLY)) >= 0) {
        puts("wanna read");
        ssize_t nc;
        while ((nc = read(fd, buf, bufsize)) != 0) {
            if (nc < 0) {
                if (errno == EINTR)
                    continue;
                else
                    break;
            }
            printf("read %zd bytes\n", nc);
            write(newfd, buf, nc);
        }
        close(fd);
        return 0;
    }
    return -1;
}