确定 C 中标准输入大小的正确/有效方法

发布于 2024-10-07 11:56:39 字数 351 浏览 2 评论 0原文

根据我之前的问题,如果标准输入来自管道终端,确定stdin大小的正确而有效的方法是什么> 在不同的系统上。

我正在执行以下操作,但是,根据一些评论,这不是正确的方法,并且它可能会或可能不会在不同的系统上工作。

#include <sys/stat.h>

off_t size(FILE *st_in) {
    struct stat st;
    if (fstat(fileno(st_in), &st) == 0)
        return st.st_size;
    return -1;
}

Based on my previous question, what would be the proper yet efficient way to determine the size of stdin if stdin is coming from a pipe or a terminal on different systems.

I was doing the following, however, based on some comments, it is not the right way, and it might or it might not work on different systems.

#include <sys/stat.h>

off_t size(FILE *st_in) {
    struct stat st;
    if (fstat(fileno(st_in), &st) == 0)
        return st.st_size;
    return -1;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

暮倦 2024-10-14 11:56:39

你不能。
想象一下 stdin 就像一个水龙头。

你问的问题和“水龙头里有多少水”是一样的吗? :-)

You can't.
Imagine stdin is like a water tap.

What you are asking is the same as "how much water is there in a tap"? :-)

够钟 2024-10-14 11:56:39

在某些系统(linux,我知道;可能是其他 *nix)下,您可以执行以下操作:

#include <unistd.h>
#include <sys/ioctl.h>

ssize_t fd_ready_size(int fd) { 
    int sz;
    int rc;

    rc = ioctl(fd, FIONREAD, &sz);
    if (rc) { // rc = -1 or 0
        return rc;
    }
    return sz;
}

对于大多数输入文件。您应该注意,我没有在这里传递 FILE * 。我这样做是因为这会产生误导。 stdio 文件可以在其中缓冲数据,这些数据需要添加到操作系统所说的准备读取的内容中。这让事情变得更加棘手,而且我不知道是否有合理的方法来获得该值。

我返回了一个ssize_t(这是一个有符号的大小类型),因为这是POSIX系统下读写返回的内容,-1代表错误情况。

如果你使用的系统不允许你这样做,并且 stat 不能给你你想要的东西,你可能不得不诉诸技巧。一种方法是尝试读取特定大小(我们将称为 X),如果您成功获取了全部数量,您可以认为“可能还有更多”并重新分配缓冲区以容纳更多内容,然后重复直到你所读到的内容并不能完全填满你的可用空间。如果您有任何类型的轮询函数可用(您可能在调用 stat 后就这样做了),那么您也可以使用它来尝试不调用读取函数,除非您确定有数据(除非您以非阻塞方式打开文件)在这种情况下并不重要)。

Under some systems (linux, I know; probably other *nix) you can do:

#include <unistd.h>
#include <sys/ioctl.h>

ssize_t fd_ready_size(int fd) { 
    int sz;
    int rc;

    rc = ioctl(fd, FIONREAD, &sz);
    if (rc) { // rc = -1 or 0
        return rc;
    }
    return sz;
}

for most any input file. You should NOTICE that I didn't pass in the FILE * here. I did this because it would have been misleading. The stdio FILE can have buffered up data in it that would need to be added to whatever the OS says is ready to be read. This makes things trickier, and I don't know off the top of my head if there is a reasonable way to get that value.

I returned a ssize_t (which is a signed size type) because that is what is returned by read and write under POSIX systems, and -1 represents the error case.

If you are using a system that doesn't allow you do that and stat doesn't give you what you want you may have to resort to tricks. One way is to attempt to read a certain size (we will call X) and if you succeed in getting this full amount you can then think "there may be a little bit more" and realloc your buffer to hold some more, and repeat until you get a read that doesn't completely fill the space you have available. If you have any type of polling function available (which you probably do since were calling stat) then you can also use that to try not to call a read function unless you are sure there is data (unless you have the file opened non-blocking in which case it doesn't matter).

陌伤ぢ 2024-10-14 11:56:39

与前面所说的相反,您可以使用stat()来确定某些操作系统中管道或流中的数据量。 但是,这并不适用于所有系统——也就是说,提供此功能并不是实现的标准做法,因此这样做是可移植的。

还有一个问题是,每当有人向其中写入更多数据时,管道大小就会发生变化,这在多任务、抢占式系统中基本上随时可能发生。

因此,虽然您可以小心翼翼地完成自己想做的事情,但这是一个薄弱且不可移植的解决方案。

当然,读取每个字节直到 EOF 或错误并计数仍然可以工作。但不确定这就是你想要的。

Contrary to what has been said, you can use stat() to determine the amount of data in a pipe or stream in some OS. This will not, however, work on all systems -- that is, it's not standard practice for the implementation to provide this functionality, so doing it this way will NOT be portable.

There's also the issue of a pipe size changing whenever someone writes more data to it, which can happen basically at any time in a multitasking, preemptive system.

So, while you can tiptoe your way around what you want to do, it's a weak and non-portable solution.

Of course, reading every byte until EOF or error, and counting, will still work. Not sure that's what you want, though.

半寸时光 2024-10-14 11:56:39

ANSI C 中的FILE 对象表示流。就我个人而言,我会将类型命名为 STREAM 而不是 FILE,但这是另一个问题。

无论如何,FILE 对象代表信息流。一些流源代表一块数据。这些源是文件和内存块。其他流源(例如管道和套接字连接)不代表数据块。它们代表(可能)无限的字节流。没有明确的开始,因为管道可能已从之前读取,然后重定向给您。也没有明确的终点,因为数据可能永远到达流中(或者至少直到有人关闭电源为止;)。

stdin 表示流的管道类型。它没有明确的开始,也没有明确的结束。因此无法可靠地测量。

如果您想知道在任何给定时间从流中读取了多少数据,则必须在 FILE 函数之上创建一些抽象层(或以某种方式挂钩 - 不要这样做)了解 ANSI C 中的此类功能),并保留自己的记录。但请注意,您无法知道从流中读取的第一个字节是从流中读取的第一个字节,因为它可能在读取后已重定向给您。

FILE objects in ANSI C represents streams. Personally, I would have named the type STREAM rather than FILE, but that's another issue.

Anyway, FILE objects represent streams of information. Some stream sources, represents a chunk of data. Such sources are files and memory blocks. Other stream sources, such as pipes and socket connections, do not represent a chunk of data. They represent a (possibly) infinite stream of bytes. There is no definite beginning, because the pipe may have been read from earlier, and later redirected to you. There is also no definite end either, because data may arrive on the stream forever and ever (or at least until someone turns off the power ;).

stdin represents a pipe type of stream. It has no definite beginning and no definite end. Therefore it cannot be measured reliably.

If you want to know at any given time how much data has been read from the stream, you'd have to create some abstraction layer ontop of the FILE functions (or somehow hook into it - don't know about such features in ANSI C), and keep your own record. Note however, that you cannot know that the first byte you read from the stream is the first byte ever to have been read from it, because it may have been redirected to you after it has been read from.

糖粟与秋泊 2024-10-14 11:56:39

尝试这样的事情:

#include <sys/stat.h> 
#include <unistd.h> 
off_t size(FILE *st_in) { 
    struct stat st; 
    off_t retval=-1;
    if (! isatty(fileno(st_in))
    {
       if (fstat(fileno(st_in), &st) == 0) 
       {
           if(S_ISREG(st.st_mode)  
              retval=st.st_size; 
       }
       else
       {
           perror("Cannot stat file");
           exit(1);
       }
    }   
    return retval; 
}

出口就在那里,可选。如果您愿意,可以在其他地方解决问题。

try something like this:

#include <sys/stat.h> 
#include <unistd.h> 
off_t size(FILE *st_in) { 
    struct stat st; 
    off_t retval=-1;
    if (! isatty(fileno(st_in))
    {
       if (fstat(fileno(st_in), &st) == 0) 
       {
           if(S_ISREG(st.st_mode)  
              retval=st.st_size; 
       }
       else
       {
           perror("Cannot stat file");
           exit(1);
       }
    }   
    return retval; 
}

The exit is there, optionally. You can handle the problems elsewhere if you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文