Правильный / Эффективный способ определения размера стандартного ввода в C - PullRequest
0 голосов
/ 10 декабря 2010

Исходя из моего предыдущего вопроса, каков будет правильный, но эффективный способ определения размера stdin, если stdin исходит от pipe или terminal в разных системах.

Я делал следующее, однако, основываясь на некоторых комментариях, это не правильный путь, и это может или не может работать в разных системах.

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

Ответы [ 5 ]

11 голосов
/ 10 декабря 2010

Вы не можете.
Представьте, что stdin похож на водопроводный кран.

То, что вы спрашиваете, равнозначно тому, "сколько воды в кране"? : -)

3 голосов
/ 10 декабря 2010

Вопреки сказанному, вы можете использовать stat() для определения объема данных в канале или потоке в некоторых ОС. Это, однако, не будет работать на всех системах - то есть реализация этой функциональности не является стандартной практикой для реализации, поэтому выполнение этого способа будет НЕ переносимым.

Существует также проблема изменения размера канала всякий раз, когда кто-то записывает в него больше данных, что может в основном происходить в любое время в многозадачной превентивной системе.

Так что, хотя вы можете на цыпочках обходить то, что хотите, это слабое и непереносимое решение.

Конечно, чтение каждого байта до EOF или ошибки и подсчет все равно будут работать. Не уверен, что это то, что вы хотите.

2 голосов
/ 10 декабря 2010

FILE объекты в ANSI C представляют потоки.Лично я бы назвал тип STREAM, а не FILE, но это другая проблема.

В любом случае, FILE объекты представляют потоки информации.Некоторые источники потоков представляют часть данных.Такими источниками являются файлы и блоки памяти.Другие источники потока, такие как каналы и соединения сокетов, не представляют порцию данных.Они представляют (возможно) бесконечный поток байтов.Определенного начала нет, потому что канал мог быть прочитан ранее, а затем перенаправлен к вам.Также нет определенного конца, потому что данные могут поступать в поток навсегда и всегда (или, по крайней мере, до тех пор, пока кто-то не отключит питание;).

stdin представляет тип потока канала.У него нет определенного начала и определенного конца.Поэтому его нельзя измерить надежно.

Если вы хотите в любой момент узнать, сколько данных было прочитано из потока, вам нужно создать некоторый уровень абстракции поверх функций FILE (иликаким-то образом подключиться к нему - не знать о таких функциях в ANSI C) и вести свой собственный учет.Однако обратите внимание, что вы не можете знать, что первый байт, который вы прочитали из потока, является первым из когда-либо прочитанных байт из него, потому что он мог быть перенаправлен вам после того, как был прочитан из.

2 голосов
/ 10 декабря 2010

В некоторых системах (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), то вы также можете использовать ее, чтобы попытаться не вызывать функцию чтения, если вы не уверены, что есть данные (если у вас нет открытого файла, не блокирующегов этом случае это не имеет значения).

0 голосов
/ 10 декабря 2010

попробуйте что-то вроде этого:

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

Выход есть, опционально.Вы можете решить проблемы в другом месте, если хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...