I'm looking at using the read() function to read in entire data structures, each of which will be of the same type as any other, but with different data, then place them into a linked list. For some reason I can't seem to find any specific information on how to terminate a loop which would include read(fp, &tmp, sizeof(struct foo))
followed by new_node(tmp)
.
I would like to be able to simply read until EOF, but I'm not aware of how to go about determining with the read() function where EOF is. Obviously, I could use a workaround with the write() function where I would include the number of structures in the file before writing, and then terminate the read function when I reach that number, but that seems a bit clunky, and avoids the original idea of knowing when the file terminates.
FOLLOW-UP:
I appreciate the assistance, and I've implemented what I've seen. Unfortunately, I believe I may be reading in the wrong information. The pertinent code:
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;
}
This is the output from the write loop:
112
1, a
112
2, b
112
3, c
112
4, d
112
5, e
The file is saved in binary, but I can make out enough to know that only the tail seems to be written, five times. I'm not sure why that is.
The output for the diagnostic printf's in the read loop is:
23728144,
23728144,
23728272,
23728272,
23728400,
23728400,
23728528,
23728528,
23728656,
23728656,
The output makes me think it's putting the value of the next pointer into the data int. Any idea why: 1) I might be write()ing the same node five times in a row? 2) I am getting gibberish when I read()?
It is conventional to use
FILE *fp;
andint fd;
(so the name for a file descriptor isfd
and notfp
).The
read()
function returns the number of bytes it read. If there's no more data, it returns 0. For disk files and the like, it will return the requested number of bytes (except at the very end when there might not be that many bytes left to read) or 0 when there's no data left to read (or -1 if there's an error on the device rather than just no more data). For terminals (and sockets, and pipes), it will read as many bytes as are available rather than wait for the requested size (so each read could return a different size). The code shown only reads full-size structures and baulks if it gets a short read, EOF or an error.The code by ensc in his answer covers all practical circumstances, but isn't the way I'd write the equivalent loop. I'd use:
The two normal cases — a full length record is read OK and EOF is detected — are handled at the top of the loop; the esoteric cases are handled further down the loop. My
err_syserr()
function isprintf()
-like and reports the error given by its arguments, and also the error associated witherrno
if it is non-zero, and then exits. You can use any equivalent mechanism. I might or might not put the file descriptor number in the error message; it depends on who is going to see the errors. If I knew the file name, I'd certainly include that in the message in preference to the file descriptor.I don't see any difficulty handling the
nbytes == -1 && errno == EINTR
case, contrary to comments by @ensc.