15

(Note: This is not a question of how to flush a write(). This is the other end of it, so to speak.)

Is it possible to empty a file descriptor that has data to be read in it without having to read() it? You might not be interested in the data, and reading it all would therefore waste space and cycles you might have better uses for.

If it is not possible in POSIX, do any operating systems have any non-portable ways to do this?

UPDATE: Please note that I'm talking about file descriptors, not streams.

Teddy
  • 6,013
  • 3
  • 26
  • 38

8 Answers8

7

If you're dealing with a tty, have a look at tcflush():

#include <termios.h>
int tcflush(int fildes, int queue_selector);

Upon successful completion, tcflush() discards data written to the object referred to by fildes (an open file descriptor associated with a terminal) but not transmitted, or data received but not read, depending on the value of queue_selector [...]

http://opengroup.org/onlinepubs/007908775/xsh/tcflush.html

squelart
  • 11,261
  • 3
  • 39
  • 43
4

For POSIX, use lseek(2) or lseek64(3) to seek ahead. For Windows, use SetFilePointer() or SetFilePointerEx().

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
2

If you know the number of bytes to skip, you can do lseek(fd, n, SEEK_CUR); for POSIX systems. There is fseek() as well, for FILE * objects. In POSIX, I think you can safely seek past the end of file, the idea is that if more data is written later, so as to make data go past the position set with lseek(), you will be able to read more data now.

Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
2

Linux 2.6.17 or later with the GNU C library version 2.5 or later contain the splice() system call, which can be used to send data from one file descriptor to another without copying it to user space. This can be used to discard data by simply opening /dev/null and spliceing data from the source file descriptor into the /dev/null file descriptor.

Teddy
  • 6,013
  • 3
  • 26
  • 38
1

Streams have fclean available, which flushes the write buffer, and returns the read buffer back to the IO system.

http://www.gnu.org/software/hello/manual/libc/Cleaning-Streams.html

If what you really want to do is skip bytes, repositioning the file pointer is the correct action. Just skip ahead as many bytes as you don't want to read.

http://www.gnu.org/software/hello/manual/libc/File-Position-Primitive.html#File-Position-Primitive

jdmichal
  • 10,984
  • 4
  • 43
  • 42
  • fclean is certainly not standard from the language point of view –  Dec 17 '09 at 20:08
  • Correct. It is part of GNU libc. I'm pretty sure that that's available in just about every OS. I updated the links to the GNU manual, instead of the mirror. – jdmichal Dec 17 '09 at 20:14
  • The prevailing answer seems to be "lseek". I'll accept your answer since you were the first to suggest it. I was hoping for something which would work on pipes, FIFOs, etc, which is why I waited, but I guess no such thing exists. – Teddy Dec 28 '09 at 13:33
  • 4
    `lseek` is the best solution for actual files, but certain file descriptors are non-seekable (e.g. pipes and fifos), so doing an `lseek` will fail. If you want the most general solution that works with all types of file descriptors, you really do need to read it into a temp buffer and discard it. For optimal performance, use a reasonably large buffer, but not so large that you blow your L1 or L2 cache. – Adam Rosenfield Dec 28 '09 at 23:14
  • Ah, I see. I agree with Adam's comment, that if `lseek` does not work, then really the only recourse is to read and discard the data. – jdmichal Jan 04 '10 at 23:05
  • This answer could be improved: The first link, which I assumed would deal with the aforementioned `fclean`, talks about `fflush()` instead. I couldn't find anything on `fclean` elsewhere. The second paragraph doesn't even mentioned the relevant function (which turns out to be `lseek()`) Therefore, the entire answer is somewhat confusing and relies completely on the linked content. – domsson May 16 '20 at 20:11
1

Neither read() nor flush() are part of Standard C or C++, but certainly none of the standard functions support flushing of input streams. I would guess this reflects something not available in the underlying operating systems. The normal way to avoid reading something altogether is to skip over it with a seek() function of some sort.

0

According to this, a POSIX system will do this on fflush(stream); .

For a stream open for reading, if the file is not already at EOF, and the file is one capable of seeking, the file offset of the underlying open file description shall be adjusted so that the next operation on the open file description deals with the byte after the last one read from or written to the stream being flushed.

Chinmay Kanchi
  • 62,729
  • 22
  • 87
  • 114
  • This governs (a) synchronizing read and write positions when interleaving buffered IO on a single file, and (b) undoing the effects of a read buffer that has proceeded ahead of what has been requested. Not what OP requests. – ephemient Dec 17 '09 at 22:20
  • That's for streams, not file descriptors. – Teddy Dec 18 '09 at 12:16
0

BSD introduced fpurge(), Solaris and glibc introduced __fpurge().
From the man page:

#include <stdio.h>
#include <stdio_ext.h>
void  __fpurge(FILE *stream);

The function __fpurge() clears the buffers of the given stream. For output streams this discards any unwritten output. For input streams this discards any input read from the underlying object but not yet obtained via getc(3); this includes any text pushed back via ungetc(3).

The function __fpurge() does precisely the same, but without returning a value.

Note, however:

These functions are nonstandard and not portable. The function fpurge() was introduced in 4.4BSD and is not available under Linux. The function __fpurge() was introduced in Solaris, and is present in glibc 2.1.95 and later.

If you're working with a file descriptor, you might be able to get a FILE* from the descriptor first.

int fd;
/* ... */
FILE* fp = fdopen(fd, "r");
/* ... */
__fpurge(fp);
domsson
  • 4,553
  • 2
  • 22
  • 40
  • I don't think this will help. It will drop whatever is in the program's own stdio buffers (which if you've just fdopen'ed will be nothing) but it won't affect data that is available to be read from the OS. – Nate Eldredge May 16 '20 at 21:33