while (read(fd, &tmp, sizeof(tmp)) == sizeof(tmp))
{
...got another one...
}
It is conventional to use FILE *fp;
and int fd;
(so the name for a file descriptor is fd
and not fp
).
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:
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);
}
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 is printf()
-like and reports the error given by its arguments, and also the error associated with errno
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.