将 对流文件的操作 转换为 对系统文件的操作

        C语言的C库提供了将 对流文件的操作 转换为 对系统文件的操作的方法。

示例:

/*
    @brief how to convert stream-file to system-file?show you here
    @author wen`xuanpei
    @email [email protected](query for any question here)
*/
#include ////EOF, FILE, stdin/stdout/stderr, fileno, fprintf, fgetc, fflush, perror, fclose
#define TEST_WAIT_GAP_BEGIN (5)
#define TEST_WAIT_GAP_END (5)

/*used by to_fd()*/
#define FLAGS_NONE (0)//
#define FLAGS_READ (1<<0)//
#define FLAGS_WRITE (1<<1)//
/*
    @brief check stream is opened or not
    @param
        fp:stream handler(been or ever been fopen(), or coredump will happen)
    @return 1:yes it is; 0:no it isn't.
*/
static int is_opened(FILE *fp){
    return fileno(fp) >= 0;
}
/*
    @brief check stream is closed or not
    @param
        fp:stream handler(been or ever been fopen(), or coredump will happen)
    @return 1:yes it is; 0:no it isn't.
*/
static int is_closed(FILE *fp){
    return -1 == fileno(fp);
}
/*
    @brief convert stream-file to system-file
        1.clean input buffer if existed and required
        2.clean output buffer if existed and required
    @param
        fp   :stream handler(been or ever been fopen(), or coredump will happen)
        flags:
            1-need clean read  buffer(FLAGS_READ)//has been read
            2-need clean write buffer(FLAGS_WRITE)//has been write
            3-need clean read or write buffer(FLAGS_WRITE | FLAGS_READ)//has been read and write
    @return -1:stream has been closed; >= 0: successful file descriptor for system-file
*/
static int to_fd(FILE*fp, int flags){
    int fd = fileno(fp);
    if(fd >= 0){//valid stream here
        /*clean input buffer inner*/
        if(flags & FLAGS_READ)
            while(EOF !=  fgetc(fp));//empty body
        /*clean output buffer inner*/
        if( (flags & FLAGS_WRITE) && EOF == fflush(fp) )
            perror("fflush");
    }
    return fd;
}

/*raw check and convert to system fd(file descriptor)*/
void test_raw(){
    fprintf(stdout, "fp(%p) => fd(%d)\n", stdin, fileno(stdin));//CLI
    fprintf(stdout, "fp(%p) => fd(%d)\n", stdout, fileno(stdout));//CLI
    fprintf(stdout, "fp(%p) => fd(%d)\n", stderr, fileno(stderr));//CLI
    fclose(stdin), fclose(stdout);
    fprintf(stderr, "fp(%p) => fd(%d)\n", stdin, fileno(stdin) );//CLI
    fprintf(stderr, "fp(%p) => fd(%d)\n", stdout, fileno(stdout) );//CLI
#if 0/*a invalid address(core dumped)*/
    FILE *fp = (FILE*)0xA234567A;
    fprintf(stderr, "fp(%p) => fd(%d)\n", fp, fileno(fp) );
#elif 0/*a null address(core dumped)*/
    FILE *fp = (FILE*)NULL;
    fprintf(stderr, "fp(%p) => fd(%d)\n", fp, fileno(fp) );
#else
    //...more exception to test if possible
#endif
}

/*wrappered check and convert to system fd(file descriptor)*/
void test_wrapper(){
    int fd0, fd1, fd2;

    fprintf(stdout, "\nbefore closed begin:\n");//CLI
    sleep(TEST_WAIT_GAP_BEGIN);
    fprintf(stdout, "opened ? stdin:%d, stdout:%d, stderr:%d\n"
    , is_opened(stdin), is_opened(stdout), is_opened(stderr));//CLI
    sleep(1);
    fprintf(stdout, "closed ? stdin:%d, stdout:%d, stderr:%d\n"
    , is_closed(stdin), is_closed(stdout), is_closed(stderr));//CLI
    sleep(1);
    fd0 = to_fd(stdin,  FLAGS_NONE);
    fd1 = to_fd(stdout, FLAGS_WRITE);
    fd2 = to_fd(stderr, FLAGS_NONE);
    fprintf(stdout, "fd0:%d, fd1:%d, fd2:%d\n", fd0, fd1, fd2);//CLI
    sleep(1);
    fprintf(stdout, "\nbefore closed end:\n");//CLI
    sleep(TEST_WAIT_GAP_END);

    fclose(stdin), fclose(stdout);//close two stream here, and buffer is closed

    fprintf(stderr, "\nafter closed begin:\n");//CLI
    sleep(TEST_WAIT_GAP_BEGIN);
    fprintf(stderr, "opened ? stdin:%d, stdout:%d, stderr:%d\n"
    , is_opened(stdin), is_opened(stdout), is_opened(stderr));//CLI
    sleep(1);
    fprintf(stderr, "closed ? stdin:%d, stdout:%d, stderr:%d\n"
    , is_closed(stdin), is_closed(stdout), is_closed(stderr));//CLI
    sleep(1);
    fd0 = to_fd(stdin,  FLAGS_NONE);
    fd1 = to_fd(stdout, FLAGS_NONE);
    fd2 = to_fd(stderr, FLAGS_NONE);//stderr has no buffer on default
    fprintf(stderr, "fd0:%d, fd1:%d, fd2:%d\n", fd0, fd1, fd2);//CLI
    sleep(1);
    fprintf(stderr, "\nafter closed end:\n");//CLI
    sleep(TEST_WAIT_GAP_END);
}

/*main frame here*/
int main (){
#if 0
    test_raw()
#else
    test_wrapper();
#endif
    return 0;
}

小结:

1)可以通过系统文件描述符,判断一个流文件是否被打开或关闭

2)一个正在使用的流文件的程序,如果需要切换到内核态,从而使用系统文件的特性功能,如果要经过转换,则需要先将流缓冲区清空(因为业务逻辑的下游将暂时不会再使用 或者 直到文件资源被回收也不会再使用)

你可能感兴趣的:(读源码,学C库,c语言)