【发布时间】:2010-12-27 19:21:30
【问题描述】:
(注意:这不是关于如何刷新write()的问题。可以说,这是它的另一端。)
是否可以清空包含要读取的数据的文件描述符而不不必read()?您可能对数据不感兴趣,因此阅读所有数据会浪费您可能有更好用途的空间和周期。
如果在 POSIX 中不可能,是否有任何操作系统有任何不可移植的方法来做到这一点?
更新:请注意,我说的是文件描述符,不是流。
【问题讨论】:
标签: c flush file-descriptor
(注意:这不是关于如何刷新write()的问题。可以说,这是它的另一端。)
是否可以清空包含要读取的数据的文件描述符而不不必read()?您可能对数据不感兴趣,因此阅读所有数据会浪费您可能有更好用途的空间和周期。
如果在 POSIX 中不可能,是否有任何操作系统有任何不可移植的方法来做到这一点?
更新:请注意,我说的是文件描述符,不是流。
【问题讨论】:
标签: c flush file-descriptor
如果您正在处理 tty,请查看tcflush():
#include <termios.h>
int tcflush(int fildes, int queue_selector);
成功完成后,tcflush() 丢弃写入对象的数据 fildes 引用(打开的文件 与终端关联的描述符) 但未发送,或接收到数据 但不读取,取决于值 queue_selector [...]
【讨论】:
对于 POSIX,使用 lseek(2) 或 lseek64(3) 向前搜索。对于 Windows,请使用 SetFilePointer() 或 SetFilePointerEx()。
【讨论】:
如果您知道要跳过的字节数,您可以为 POSIX 系统执行lseek(fd, n, SEEK_CUR);。还有fseek(),用于FILE * 对象。在 POSIX 中,我认为您可以安全地查找文件末尾,其想法是,如果稍后写入更多数据,以便使数据超过 lseek() 设置的位置,您现在可以读取更多数据.
【讨论】:
带有 GNU C 库版本 2.5 或更高版本的 Linux 2.6.17 或更高版本包含 splice() 系统调用,可用于将数据从一个文件描述符发送到另一个文件描述符无需将其复制到用户空间时间>。这可用于丢弃数据,只需将源文件描述符中的/dev/null 和spliceing 数据打开到/dev/null 文件描述符中即可。
【讨论】:
流有 fclean 可用,它刷新写缓冲区,并将读缓冲区返回给 IO 系统。
http://www.gnu.org/software/hello/manual/libc/Cleaning-Streams.html
如果您真正想做的是跳过字节,则重新定位文件指针是正确的操作。只需向前跳过不想读取的字节即可。
http://www.gnu.org/software/hello/manual/libc/File-Position-Primitive.html#File-Position-Primitive
【讨论】:
lseek 是实际文件的最佳解决方案,但某些文件描述符是不可搜索的(例如管道和 fifos),因此执行lseek 将失败。如果您想要适用于所有类型文件描述符的最通用解决方案,您确实需要将其读入临时缓冲区并丢弃它。为获得最佳性能,请使用相当大的缓冲区,但不要太大,以免耗尽 L1 或 L2 缓存。
lseek 不起作用,那么唯一的办法就是读取并丢弃数据。
read() 和 flush() 都不是标准 C 或 C++ 的一部分,但当然没有一个标准函数支持输入流的刷新。我猜这反映了底层操作系统中不可用的东西。避免完全阅读某些内容的正常方法是使用某种 seek() 函数跳过它。
【讨论】:
根据this,POSIX 系统将在fflush(stream); 上执行此操作。
对于一个打开读取的流,如果文件还没有处于EOF,并且该文件是可以查找的,则需要调整底层打开文件描述的文件偏移量,以便对打开文件描述进行下一步操作处理最后一个读取或写入正在刷新的流之后的字节。
【讨论】:
BSD 引入fpurge(),Solaris 和glibc 引入__fpurge()。
来自man page:
#include <stdio.h>
#include <stdio_ext.h>
void __fpurge(FILE *stream);
函数 __fpurge() 清除给定流的缓冲区。对于输出流,这会丢弃任何未写入的输出。对于输入流,这将丢弃从底层对象读取但尚未通过 getc(3) 获得的任何输入;这包括通过 ungetc(3) 推回的任何文本。
函数 __fpurge() 的作用完全相同,但没有返回值。
但是请注意:
这些函数是非标准的,不可移植。 fpurge() 函数是在 4.4BSD 中引入的,在 Linux 下不可用。函数 __fpurge() 是在 Solaris 中引入的,并且存在于 glibc 2.1.95 及更高版本中。
如果您正在使用文件描述符,您可以先使用get a FILE* from the descriptor。
int fd;
/* ... */
FILE* fp = fdopen(fd, "r");
/* ... */
__fpurge(fp);
【讨论】: