【问题标题】:Empty or "flush" a file descriptor without read()?清空或“刷新”没有 read() 的文件描述符?
【发布时间】:2010-12-27 19:21:30
【问题描述】:

(注意:这不是关于如何刷新write()的问题。可以说,这是它的另一端。)

是否可以清空包含要读取的数据的文件描述符而不不必read()?您可能对数据不感兴趣,因此阅读所有数据会浪费您可能有更好用途的空间和周期。

如果在 POSIX 中不可能,是否有任何操作系统有任何不可移植的方法来做到这一点?

更新:请注意,我说的是文件描述符不是流。

【问题讨论】:

    标签: c flush file-descriptor


    【解决方案1】:

    如果您正在处理 tty,请查看tcflush()

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

    成功完成后,tcflush() 丢弃写入对象的数据 fildes 引用(打开的文件 与终端关联的描述符) 但未发送,或接收到数据 但不读取,取决于值 queue_selector [...]

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

    【讨论】:

    • 谢谢,正是我想要的!
    【解决方案2】:

    对于 POSIX,使用 lseek(2)lseek64(3) 向前搜索。对于 Windows,请使用 SetFilePointer()SetFilePointerEx()

    【讨论】:

      【解决方案3】:

      如果您知道要跳过的字节数,您可以为 POSIX 系统执行lseek(fd, n, SEEK_CUR);。还有fseek(),用于FILE * 对象。在 POSIX 中,我认为您可以安全地查找文件末尾,其想法是,如果稍后写入更多数据,以便使数据超过 lseek() 设置的位置,您现在可以读取更多数据.

      【讨论】:

        【解决方案4】:

        带有 GNU C 库版本 2.5 或更高版本的 Linux 2.6.17 或更高版本包含 splice() 系统调用,可用于将数据从一个文件描述符发送到另一个文件描述符无需将其复制到用户空间时间>。这可用于丢弃数据,只需将源文件描述符中的/dev/nullspliceing 数据打开到/dev/null 文件描述符中即可。

        【讨论】:

          【解决方案5】:

          流有 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

          【讨论】:

          • fclean 从语言的角度来看肯定不是标准的
          • 正确。它是 GNU libc 的一部分。我很确定这在几乎所有操作系统中都可用。我更新了指向 GNU 手册的链接,而不是镜像。
          • 普遍的答案似乎是“lseek”。我会接受您的回答,因为您是第一个提出建议的人。我希望能在管道、FIFO 等上工作的东西,这就是我等待的原因,但我想不存在这样的东西。
          • lseek 是实际文件的最佳解决方案,但某些文件描述符是不可搜索的(例如管道和 fifos),因此执行lseek 将失败。如果您想要适用于所有类型文件描述符的最通用解决方案,您确实需要将其读入临时缓冲区并丢弃它。为获得最佳性能,请使用相当大的缓冲区,但不要太大,以免耗尽 L1 或 L2 缓存。
          • 啊,我明白了。我同意 Adam 的评论,如果 lseek 不起作用,那么唯一的办法就是读取并丢弃数据。
          【解决方案6】:

          read() 和 flush() 都不是标准 C 或 C++ 的一部分,但当然没有一个标准函数支持输入流的刷新。我猜这反映了底层操作系统中不可用的东西。避免完全阅读某些内容的正常方法是使用某种 seek() 函数跳过它。

          【讨论】:

            【解决方案7】:

            根据this,POSIX 系统将在fflush(stream); 上执行此操作。

            对于一个打开读取的流,如果文件还没有处于EOF,并且该文件是可以查找的,则需要调整底层打开文件描述的文件偏移量,以便对打开文件描述进行下一步操作处理最后一个读取或写入正在刷新的流之后的字节。

            【讨论】:

            • 这控制 (a) 在单个文件上交错缓冲 IO 时同步读取和写入位置,以及 (b) 撤消在请求之前进行的读取缓冲区的影响。不是 OP 要求的。
            • 那是流,不是文件描述符。
            【解决方案8】:

            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);
            

            【讨论】:

            • 我认为这不会有帮助。它会丢弃程序自己的 stdio 缓冲区中的任何内容(如果您刚刚 fdopen'ed 将什么都没有),但不会影响可从操作系统读取的数据。
            猜你喜欢
            • 2019-06-11
            • 1970-01-01
            • 2019-11-17
            • 1970-01-01
            • 2023-04-02
            • 2010-09-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多