1. 文件描述符與文件指針
文件描述符:在linux系統中打開文件就會獲得文件描述符,它是個很小的正整數。每個進程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是這個表的索引,每個表項都有一個指向已打開文件的指針。套接字和管道都是文件描述符。
文件指針:C標準庫中使用文件指針做爲文件I/O的句柄。文件指針指向進程用戶區中的一個被稱爲FILE結構的數據結構。FILE結構包括一個緩衝區和一 個文件描述符。而文件描述符是文件描述符表的一個索引,因此從某種意義上說文件指針就是句柄的句柄(在Windows系統上,文件描述符被稱作文件句 柄)。stderr、stdout、stdin都是文件指針。
2. 基於文件描述符的I/O函數
基於文件描述符的I/O函數有:open, close, read, write, getc, getchar, putc, putchar等。他們屬於系統調用,更接近於硬件,屬於非緩衝文件系統的IO函數。
非緩衝文件系統依賴於操作系統,通過操作系統的功能對文件進行讀寫,是系統級的輸入輸出,它不設文件結構體指針,只能讀寫二進制文件(對於UNIX系統內核而言,文本文件和二進制代碼文件並無區別),但效率高、速度快。由於ANSI標準不再包括非緩衝文件系統,因此,在讀取正規的文件時,建議大家最好不要選擇它。
1)open/close:open打開文件,返回一個文件描述符;close關閉打開的文件。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
#include <unistd.h>
int close(int fd);
2)read/write:文件的讀寫操作,向給定的文件描述符讀取或者寫入數據塊,操作的都是二進制數據。
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
3. 基於文件指針的I/O函數
基於文件指針的I/O函數有:fopen,fclose,fread,fwrite,fgetc,fgets,fputc,fputs,freopen,fseek,ftell,rewind, fprintf等。他們屬於庫函數,是對open,write等系統調用的封裝,屬於緩衝文件系統的I/O函數。
緩衝文件系統是藉助於文件結構體指針FILE *來對文件進行管理,通過文件指針對文件進行訪問,即可以讀寫字符、字符串、格式化數據,也可以讀寫二進制數據。
1)fopen/fclose:打開或關閉文件。
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
FILE *fdopen(int fildes, const char *mode);
FILE *freopen(const char *path, const char *mode, FILE *stream);
#include <stdio.h>
int fclose(FILE *fp);
2)fread/fwrite/fgetc/fgets/fputc/fputs:通過文件指針讀寫文件。
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
#include <stdio.h>
int fgetc(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
int getc(FILE *stream);
int getchar(void);
char *gets(char *s);
int ungetc(int c, FILE *stream);
#include <stdio.h>
int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);
int puts(const char *s);
3)fseek/ftell/rewind:獲取或者重置文件操作位置。
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
int fgetpos(FILE *stream, fpos_t *pos);
int fsetpos(FILE *stream, fpos_t *pos);
4)fprintf/sprintf/snprintf:格式化輸出函數
#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
5)scanf/fscanf/sscanf:格式化輸入函數
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
PS: 用fread和fwrite,它自動分配緩存,速度會很快,比自己來做要簡單。如果要處理一些特殊的描述符,用read和write,如套接口,管道之類的。
實例:
[root@HPC-NQS file_io]# cat file_read.c
#include <stdio.h>
#define MAX_LINE 1024
int main (int argc, char* argv[])
{
FILE *fp;
char s[MAX_LINE];
fp=fopen(argv[1],"r");
printf("current position:%ld .\n",ftell(fp));
printf("first line is:%s\n",fgets(s,MAX_LINE,fp));
printf("current position:%ld .\n",ftell(fp));
printf("some character folow:\n%c%c%c\n",fgetc(fp),fgetc(fp),fgetc(fp));
printf("current position:%ld .\n",ftell(fp));
rewind(fp);
printf("position after rewind:%ld .\n",ftell(fp));
fseek(fp,0,SEEK_END);
printf("position after fseek(fp,0,SEEK_END):%ld .\n",ftell(fp));
return 0;
}
輸出結果:
[root@HPC-NQS file_io]# ./file_read file_read.c
current position:0 .
first line is:#include <stdio.h>
current position:19 .
some character folow:
d#
current position:22 .
position after rewind:0 .
position after fseek(fp,0,SEEK_END):613 .