Прочетете от тръба ред по ред в 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)


Това обикновено се нарича просто четене от stdin. Програмата не трябва да се интересува дали входът е канал, пренасочен файл или клавиатура.

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