Чтение из конвейера построчно в C

Как я могу отделить линии, идущие от трубы. В трубе есть такой текст:

HALLO:500\n
TEST:300\N
ADAD
ADAWFFA
AFAGAGAEG

Я хочу отделить строки от канала, потому что хочу сохранить значения в переменных.

Вот мой код c:

#include <stdio.h>
#include <stdlib.h>

#define BUFFERSIZE    1

int main(int argc, char **argv){
    unsigned char     buffer[BUFFERSIZE];
    FILE                         *instream;
    int                            bytes_read=0;
    int                            buffer_size=0;


    buffer_size=sizeof(unsigned char)*BUFFERSIZE;
    /* open stdin for reading */
    instream=fopen("/dev/stdin","r");

    /* did it open? */
    if(instream!=NULL){
        /* read from stdin until it's end */
        while((bytes_read=fread(&buffer, buffer_size, 1, instream))==buffer_size){
            fprintf(stdout, "%c", buffer[0]);
        }
    }
    /* if any error occured, exit with an error message */
    else{
        fprintf(stderr, "ERROR opening stdin. aborting.\n");
        exit(1);
    }

    return(0);
}

Это правильный способ чтения из канала для лучшей строки за строкой?


person bladepit    schedule 23.04.2013    source источник
comment
for the best - субъективный вопрос. Вы действительно столкнулись с какой-либо проблемой?   -  person abasu    schedule 23.04.2013
comment
Замените fread на fgets.   -  person Anish Ramaswamy    schedule 23.04.2013


Ответы (2)


Обычно это просто называется чтением со стандартного ввода. Программе все равно, является ли ввод каналом, перенаправленным файлом или клавиатурой.

fread будет просто читать до тех пор, пока буфер не заполнится. Используйте fgets для чтения строки.

Также размер буфера должен быть достаточно большим, чтобы вместить строку. Для небольших одноразовых программ вы можете просто выбрать номер. Или есть стандартное имя BUFSIZ, которое дает вам довольно большой буфер. Насколько велик? Достаточно большой. Действительно? Вероятно.

fgets скопирует символ новой строки в строку, если только строка не заполнится первой. Таким образом, вы можете проверить последний символ, чтобы определить, была ли строка усечена или нет. При разумных вкладах этого не произойдет. Но более надежным подходом было бы выделение буфера большего размера, копирование частичной строки и повторный вызов fgets, чтобы продолжить попытки получить полную строку.

#include <stdio.h>

int main() {
    char buf[BUFSIZ];
    fgets(buf, sizeof buf, stdin);
    if (buf[strlen(buf)-1] == '\n') {
        // read full line
    } else {
        // line was truncated
    }
    return 0;
}

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

person luser droog    schedule 23.04.2013
comment
Я бы. Но вы должны научиться делать man fgets для себя. (Это первое, что я бы сделал, чтобы написать пример. Я всегда получаю аргументы в обратном порядке, когда пишу без проверки.) - person luser droog; 23.04.2013
comment
Я не пытаюсь показаться сопливым. Я действительно думаю, что мне лучше не писать такой пример. - person luser droog; 23.04.2013
comment
@bladepit, Или вам поможет онлайн-руководство :) - person Anish Ramaswamy; 23.04.2013
comment
Да, это верно. Я смотрю на руководство и надеюсь, что до вечера я решил свою проблему - person bladepit; 23.04.2013
comment
последний вопрос: с помощью fgets мне нужно указать длину строки, которую я читаю? - person bladepit; 23.04.2013
comment
Вам нужно указать максимальную длину. Он остановится на новой строке. О, хорошо, я добавлю больше к ответу. Но у вас всегда должны быть установлены справочные страницы. Они супер полезные. - person luser droog; 23.04.2013
comment
Кроме BUFSIZ есть еще LINE_MAX (<limits.h>). На моей машине меньше (2048 против 8192). - person wastl; 14.08.2019

Вот еще один вариант (я не совсем уверен, что это "правильный" способ) - использовать количество байтов, прочитанных функцией read. В этом примере я читал из stdin, хотя было сделано перенаправление, поэтому fd в 0 — это файл/канал/что вам нужно.

  while ((nbytes=read(STDIN_FILENO, buffer, MAX_PIPE_SIZE)) > 0) {
    write(STDOUT_FILENO, buffer, nbytes);
  }
person didinino    schedule 16.12.2015