Proper/Efficient way to determine size of stdin in C

落花浮王杯 提交于 2020-11-29 03:53:12

问题


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;
}

回答1:


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"? :-)




回答2:


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.




回答3:


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).




回答4:


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.




回答5:


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.



来源:https://stackoverflow.com/questions/4411852/proper-efficient-way-to-determine-size-of-stdin-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!