流和FILE對象
對於標準I/O庫,其操作是針對流(stream)進行的。當用標準I/O庫打開或創建一個文件時,既已使一個流與一個文件相關聯。
流的定向(stream’s orientation)
流的定向決定了所讀、寫的字符是單字節還是多字節的。當一個流最初被創建時,它未被定向。如果在一個未定向的流上使用一個單字節I/O函數,則將流的定向被設置爲字節定向的。如果在一個未定向的流上使用一個多字節I/O函數,則將流的定向被設置爲寬定向(多字節)的。
只有兩個函數能夠改變流的定向。freopen函數清除一個流的定向;fwide函數設置流的定向。
#include <wchar.h>
int fwide(FILE *stream, int mode);
返回值:若流是寬定向的則返回正值,若流是字節定向的則返回負值,若流是未定向的則返回0.
fwide函數由通過mode參數決定流的定向:
- 若 mode > 0,將流設置爲寬定向的;
- 若 mode < 0,將流設置爲字節定向的;
- 若 mode = 0,不設置流的定向,但是返回標識該流定向的值。
例1. 使用fwide設置流的定向
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
int main(int argc, char *argv[])
{
FILE *fp;
int wd = 0;
int wide = 0;
if (argc != 3){
printf("Usage: %s <path> <wide>\n", argv[0]);
exit(1);
}
fp = fopen(argv[1], "r");
if (!fp){
printf("Open stream failed\n");
exit(-1);
}
wide = atoi(argv[2]);
wd = fwide(fp, wide);
if (wd > 0)
printf("%d : stream is wide-character oriented.\n", wd);
else if (wd < 0)
printf("%d : stream is byte oriented.\n", wd);
else
printf("%d : stream has no orientation yet.\n", wd);
fclose(fp);
return 0;
}
將流設置爲字節定向的:
$ ./a.out file -3
-1 : stream is byte oriented.
將流設置爲寬定向的:
$ ./a.out file 3
1 : stream is wide-character oriented.
獲取流的定向:
$ ./a.out file 0
0 : stream has no orientation yet.
當打開一個流時,標準I/O函數fopen返回一個指向FILE對象的指針。該對象是一個結構體,它包含了標準I/O庫爲管理流所需的所有信息,包括:用於實際I/O的文件描述符、指向該流緩衝區的指針、緩衝區的長度、當前在緩衝區的字符數以及出錯標誌等。
FILE結構體定義:
[ /usr/include/libio.h ]
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
[ /usr/include/stdio.h ]
__BEGIN_NAMESPACE_STD
/* The opaque type of streams. This is the definition used elsewhere. */
typedef struct _IO_FILE FILE;
__END_NAMESPACE_STD
標準輸入、標準輸出和標準出錯
對一個進程預定義了三個流,且這三個流能自動被進程使用,它們是標準輸入、標準輸出和標準出錯。
這三個標準I/O流通過預定義文件指針stdin、stdout和stderr加以引用。這三個指針同樣在stdio.h中定義。
/* Standard streams. */
extern struct _IO_FILE *stdin; /* Standard input stream. */
extern struct _IO_FILE *stdout; /* Standard output stream. */
extern struct _IO_FILE *stderr; /* Standard error output stream. */
/* C89/C99 say they're macros. Make them happy. */
#define stdin stdin
#define stdout stdout
#define stderr stderr