开发者

Proper/Efficient way to determine size of stdin in C

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 comme开发者_运维百科nts, 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;
}


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


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.


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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜