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 .