2013-12-01 11 views
1

Я ищу функцию read() для чтения во всех структурах данных, каждая из которых будет иметь тот же тип, что и любой другой, но с разными данными, затем поместите их в связанный список. По какой-то причине я не могу найти никакой конкретной информации о том, как завершить цикл, который будет включать read(fp, &tmp, sizeof(struct foo)), а затем new_node(tmp).Операции множественного чтения() в том же файле

Я хотел бы иметь возможность просто читать до EOF, но я не знаю, как это сделать с помощью функции read(), где есть EOF. Очевидно, что я мог бы использовать обходной путь с функцией write(), в которой я бы включил количество структур в файл перед записью, а затем прекратил функцию чтения, когда я достиг этого числа, но это кажется немного неуклюжим и позволяет избежать первоначального идея знать, когда файл завершается.

FOLLOW-UP:

Я ценю помощь, и я реализовал то, что я видел. К сожалению, я считаю, что могу читать неверную информацию. Соответствующий код:

struct test_t{ 
    int data; 
    char buf[LEN]; 
     struct test_t * next; 
}; 

struct test_t * new_node(struct test_t node, struct test_t * tail) 
{ 
    struct test_t * tmp = NULL; 

    if(!(tmp = malloc(sizeof(struct test_t)))) 
     return NULL; 

    tmp->data = node.data; 
    strcpy(tmp->buf, node.buf); 
    tmp->next = NULL; 
    if(tail) 
     tail->next = tmp; 

    return tmp; 
} 

... 

while(read(fd, &tmp, sizeof(struct test_t)) == sizeof(struct test_t)){ 
    printf("%d, %s\n", tmp.data, tmp.buf); 
    tail = new_node(tmp, tail); 
    if(head == NULL) 
     head = tail; 
    printf("%d, %s\n", tail->data, tail->buf); 
} 

... 

fd = open("test.txt", O_WRONLY | O_CREAT, 0666); 
iter = head; 
while(iter){ 
    printf("%d\n", write(fd, &iter, sizeof(struct test_t))); 
    printf("%d, %s\n", iter->data, iter->buf); 
    iter = iter->next; 
} 

Это выход из цикла записи:

112 
1, a 
112 
2, b 
112 
3, c 
112 
4, d 
112 
5, e 

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

Выход для диагностики PRINTF годов в цикле чтения является:

23728144, 
23728144, 
23728272, 
23728272, 
23728400, 
23728400, 
23728528, 
23728528, 
23728656, 
23728656, 

Выход заставляет меня думать, что это положить значение следующего указателя в междунар данных. Любая идея, почему: 1) Я мог бы писать() на том же узле пять раз подряд? 2) Я получаю тарабарщину, когда читаю()?

+2

Может проверить возвращаемое значение 'чтения()'? – wildplasser

ответ

2
while (read(fd, &tmp, sizeof(tmp)) == sizeof(tmp)) 
{ 
    ...got another one... 
} 

Общепринято использовать FILE *fp; и int fd; (так что имя для дескриптора файла является fd и не fp).

Функция read() возвращает количество прочитанных байтов. Если данных больше нет, он возвращает 0. Для файлов с дисками и т. П. Он вернет запрошенное количество байтов (за исключением самого конца, когда может не хватить столько байтов для чтения) или 0, когда нет данных для чтения (или -1, если на устройстве есть ошибка, а не просто больше данных). Для терминалов (и сокетов, и труб) он будет считывать столько байтов, сколько доступно, а не ждать требуемого размера (поэтому каждое чтение может возвращать другой размер). Показанный код показывает только полноразмерные структуры и балки, если он получает короткое чтение, EOF или ошибку.


Код по ensc в его answer охватывает все практические обстоятельства, но это не так, как я бы написать эквивалентный цикл. Я хотел бы использовать:

struct foo tmp; 
ssize_t nbytes; 

while ((nbytes = read(fd, &tmp, sizeof(tmp))) != 0) 
{ 
    if ((size_t)nbytes = sizeof(tmp)) 
     process(&tmp); 
    else if (nbytes < 0 && errno == EINTR) 
     continue; 
    else if (nbytes > 0) 
     err_syserr("Short read of %zu bytes when %zu expected on fd %d\n", 
        nbytes, sizeof(tmp), fd); 
    else 
     err_syserr("Read failure on fd %d\n", fd); 
} 

двух обычных случаях - полная длина записи считывается OK и EOF обнаруживается - обрабатываются в верхней части петли; эзотерические случаи обрабатываются дальше по петле. Моя функция err_syserr() равна printf()-like и сообщает об ошибке, заданной ее аргументами, а также ошибку, связанную с errno, если она отлична от нуля, а затем завершается. Вы можете использовать любой эквивалентный механизм.Я мог бы или не мог бы поместить номер дескриптора файла в сообщение об ошибке; это зависит от того, кто будет видеть ошибки. Если бы я знал имя файла, я бы, конечно, включил это в сообщение, предпочитая дескриптор файла.

У меня нет проблем с обработкой футляра nbytes == -1 && errno == EINTR, в отличие от комментариев от @ensc.

2

чтение возвращает количество прочитанных байтов. Если вы выполняете чтение, а возвращаемое значение меньше количества запрошенных байтов, то вы знаете, что он достиг EOF во время этого чтения. Если он точно равен запрашиваемому количеству байтов, то либо файл не достигнет EOF, либо он сделал это, и в файле осталось ровно 0 байтов, и в этом случае следующий вызов read() вернет 0.

while(read(fd, &tmp, sizeof(tmp)) > 0) { 
    ... 
} 
2
for (;;) { 
    struct foo tmp; 
    ssize_t l = read(fd, &tmp, sizeof tmp); 

    if (l < 0 && errno == EINTR) { 
     continue; 
    } else if (l < 0) { 
     perror("read()"); 
     abort(); 
    } else if (l == 0) { 
     break; /* eof condition */ 
    } else if ((size_t)(l) != sizeof tmp) { 
     abort(); /* something odd happened */ 
    } else { 
     handle(&tmp); 
    } 
} 

EDIT:

В своих проектах я использую функцию универсального

bool read_all(int fd, void *dst_, size_t len, bool *is_err) 
{ 
     unsigned char *dst = dst_; 

     *is_err = false; 

     while (len > 0) { 
       ssize_t l = read(fd, dst, len); 

       if (l > 0) { 
         dst += l; 
         len -= l; 
       } else if (l == 0) { 
         com_err("read_all", 0, "read(): EOF"); 
         *is_err = (void *)dst != dst_; 
         break; 
       } else if (errno == EINTR) { 
         continue; 
       } else { 
         com_err("read_all", errno, "read()"); 
         *is_err = true; 
         break; 
       } 
     } 

     return len == 0; 
} 

. Поскольку я предпочитаю подход, чтобы сказать, сколько элементов нужно читать, EOF обрабатывается здесь как ошибка. Но было бы тривиально добавить еще один аргумент bool *err в функцию, установленную в случае ошибки, отличной от EOF. Вы можете использовать выше как

while (read_all(fd, &tmp, sizeof tmp, &is_err)) 
    new_node(&tmp); 
+1

Когда read() получает последний раздел данных, не будет ли он возвращать число между 0 и sizeof (tmp)? Если, конечно, размер файла оказывается кратным sizeof (tmp)? Потому что если так, то это не странно для l! = Sizeof (tmp). –

+1

@master_latch: подходит ли 'abort()', является спорным, но это охватывает много, если не все, возможных условий ошибки. Лично я бы не кодировал его как бесконечный цикл; Я бы, вероятно, использовал 'while ((l = read (fd, & tmp, sizeof (tmp)))! = 0) {...}', опустив обнаружение EOF из тела цикла, потому что условие цикла обнаруживает, что , Я бы также положил нормальный регистр вверху: 'if (l == sizeof (tmp)) {handle (&tmp);} else ... обрабатывать ошибки ...'. –

+0

было бы плохой дизайн, если такой макет файла, который должен содержать точно * n * элементов и заканчивается сразу, или вы помещаете в файл информацию о том, сколько элементов * n * следует ожидать и читать только так. – ensc

2

Игнорирование условий ошибок, я думаю, что это основная идея:

while (read(fp, &tmp, sizeof(struct foo))==sizeof(struct foo)) 
    new_node(tmp); 

 Смежные вопросы

  • Нет связанных вопросов^_^