ftell(FILE * fd)和lseek(int fd,off_t offset,int whence)结果之间的差异 [英] Difference between result of ftell(FILE* fd) and lseek(int fd, off_t offset, int whence)

查看:135
本文介绍了ftell(FILE * fd)和lseek(int fd,off_t offset,int whence)结果之间的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    //this file exists and contains data: "ABCDEFGHIJKLM"
    FILE* file = fopen("file.txt", "r");
    char data[4];
    long int pos = ftell(file);
    fseek(file, 0, SEEK_SET);
    fread(data, 4, 1, file);
    fseek(file, pos, SEEK_SET);

    printf("ftell: %d\n", ftell(file));
    printf("lseek: %d\n", lseek(fileno(file), 0, SEEK_CUR));

    fread(data, 1, 4, file);

    //this correctly prints A
    //but external function needs fileno(file) that has wrong pos
    printf("%c\n", data[0]);

    fclose(file);
    return 0;
}

该程序的结果令人惊讶:

ftell: 0
lseek: 14
A

我正在尝试修复应用程序中的错误,但我确定该程序的前一段时间应为0, 0(换句话说,我的应用程序中从来没有这个错误). /p>

这种奇怪的情况在libc中发生了什么变化?

我如何才能很好地解决此问题?

lseek(fileno(file), 0, SEEK_SET)是一个好的解决方案吗?

解决方案

同时使用标准库文件操作(例如fread(3)fseek(3))和低级系统调用(例如read(2)lseek(3)).

这是有问题的,原因是标准库将缓冲内容,而不是立即将它们实际写出(写入文件描述符)(取决于缓冲模式).

如果您需要访问基础文件描述符,则应确保注释,您也许可以将FILE*与文件描述符重新同步,如下所示:

/**
 * Re-synchronize the file offset of a FILE with the
 * file offset of its underlying file descriptor.
 */
static inline void fresync(FILE *f)
{
    off_t off = lseek(fileno(f), 0, SEEK_CUR);
    fseek(f, off, SEEK_SET);
}

Consider this sample of code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    //this file exists and contains data: "ABCDEFGHIJKLM"
    FILE* file = fopen("file.txt", "r");
    char data[4];
    long int pos = ftell(file);
    fseek(file, 0, SEEK_SET);
    fread(data, 4, 1, file);
    fseek(file, pos, SEEK_SET);

    printf("ftell: %d\n", ftell(file));
    printf("lseek: %d\n", lseek(fileno(file), 0, SEEK_CUR));

    fread(data, 1, 4, file);

    //this correctly prints A
    //but external function needs fileno(file) that has wrong pos
    printf("%c\n", data[0]);

    fclose(file);
    return 0;
}

Result of this program is surprising:

ftell: 0
lseek: 14
A

I'm trying to fix bug in my application, but I'm sure that some time ago result of this program should be 0, 0 (in other words, never before has there been this error in my app).

What changed in libc that this weird situation occurs?

How I can fix this in good way?

Is lseek(fileno(file), 0, SEEK_SET) a good solution?

解决方案

It is dangerous to use both standard library file operations (e.g. fread(3), fseek(3)) along with low-level system calls (e.g. read(2), lseek(3)).

The reason this is problematic is because the standard library will buffer things, and not actually write them out (to the file descriptor) immediately (depending on the buffering mode).

If you need to access the underlying file descriptor, you should be sure to fflush the stream before getting its fileno. I've thrown something like this in a header file:

/**
 * Safely get the file descriptor associated with FILE,
 * by fflush()ing its contents first.
 */
static inline int safe_fileno(FILE *f)
{
    fflush(f);
    return fileno(f);
}

Also, once you call this, you probably shouldn't go back to using the FILE* again, because you've changed the kernel file pointer, but the standard library may assume it is unchanged (since you last fflushed it). As was mentioned in a comment, you may be able to re-sync the FILE* with the file descriptor like this:

/**
 * Re-synchronize the file offset of a FILE with the
 * file offset of its underlying file descriptor.
 */
static inline void fresync(FILE *f)
{
    off_t off = lseek(fileno(f), 0, SEEK_CUR);
    fseek(f, off, SEEK_SET);
}

这篇关于ftell(FILE * fd)和lseek(int fd,off_t offset,int whence)结果之间的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆