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