标准IO和系统调用IO的区别
- 标准IO通过系统调用IO实现,标准IO可以扩平台,一般优先使用标准IO
标准IO和系统调用IO的区别如下表:
标准IO | 系统调用IO | |
---|---|---|
帮助(man手册) | man 3 | man 2 |
文件描述符 | FILE 类型的流 | int 类型文件描述符 |
缓存 | 行缓存、全缓存、不缓存 | 不带缓存 |
标准IO常用的函数和注意项
-
FILE* 流
贯穿STDIO全局的一个结构体,很重要!
-
打开和关闭文件(fopen/fclose)
函数说明:
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
FILE *fdopen(int fd, const char *mode); //有用
FILE *freopen(const char *path, const char *mode, FILE *stream);
关于mode:
r Open text file for reading. The stream is positioned at the beginning of the file. (要求文件必须存在)
r+ Open for reading and writing. The stream is positioned at the beginning of the file.(要求文件必须存在)
w Truncate file to zero length or create text file for writing. The stream is positioned at
the beginning of the file.
w+ Open for reading and writing. The file is created if it does not exist, otherwise it is
truncated. The stream is positioned at the beginning of the file.
a Open for appending (writing at end of file). The file is created if it does not exist.
The stream is positioned at the end of the file.
a+ Open for reading and appending (writing at end of file). The file is created if it does
not exist. The initial file position for reading is at the beginning of the file, but out‐
put is always appended to the end of the file.(读和写的位置是不同的)
几个注意点:
在windows环境下需要注意加’b’,识别二进制文件,而在Linux/UNIX中不需要考虑这个问题;
只识别以上面字符开头的mode字符串,如’readwrite’只识别’r’;
自动创建的文件将具有umak定义的默认权限,可用umask修改;默认权限:S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666) |
那么fopen返回的FILE,存放在哪里?堆。一般来说,有对应逆操作的函数,都会放在堆上。
关于freopen(const char *path, const char *mode, FILE *stream)
函数,一般用于修改stderr,stdout 到一个文件,如下所示:
#include <stdio.h>
#include <stdlib.h>
int main(void){
FILE * f;
f = freopen("/tmp/test", "a", stderr);
fprintf(stderr, "test for freopen()\n");
fclose(f);
return 0;
}
FILE *fdopen(int fd, const char *mode)
,将一个文件描述符转换为一个FILE流,比如将socket文件描述符转换为FILE流,用标准IO函数来处理socket。
-
读写文件
有这么多个函数:fget/fput/fgetc/fputc/fgets/fputs/fread/fwrite 有几个注意的问题: - getc是宏,fgetc是函数,一般用函数 - fread/fwrite,其中的size最好为1,如fread(buf,1,10,fp)
多练习,很重要。
-
输入输出
#include <stdio.h> int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); //打印到FILE,如stderr int sprintf(char *str, const char *format, ...); // 打印到字符串 int snprintf(char *str, size_t size, const char *format, ...);
来一个fprintf的小例子,sprintf.c
#include <stdio.h> int scanf(const char *format, ...); // 慎重使用%s int fscanf(FILE *stream, const char *format, ...); int sscanf(const char *str, const char *format, ...);
-
文件位置定位
#include <stdio.h> int fseek(FILE *stream, long offset, int whence); //long long ftell(FILE *stream); // long 没有说明,大小不好说,超过2G会有问题 void rewind(FILE *stream); int fgetpos(FILE *stream, fpos_t *pos); int fsetpos(FILE *stream, fpos_t *pos);
有两个函数解决这个问题,但是方言…
#include <stdio.h> int fseeko(FILE *stream, off_t offset, int whence); //不用long,使用off_t off_t ftello(FILE *stream); On many architectures both off_t and long are 32-bit types, but compilation with #define _FILE_OFFSET_BITS 64 will turn off_t into a 64-bit type. #需要添加 CFLAGS+=-D_FILE_OFFSET_BITS=64 到makefile
那如果文件真的超过2G,怎么办?不知道
如何获取文件的长度?fseek.c
-
缓冲区刷新
缓冲区可以合并系统调用 * 行缓冲:换行或缓冲区满,强制刷新 (stdout) * 全缓冲:缓冲区满,刷新(默认模式,但不是终端) * 无缓冲:立即输出(stderr)
强制刷新缓冲区函数,fflush.c
设置缓冲区函数setvbuf,绝大多数不需要修改缓冲区,知道就好了,setvbuf.c
-
直接获取一行内容的函数 getline
#define _GNU_SOURCE //需要,但是这么写不好看,也很麻烦 #include <stdio.h> ssize_t getline(char **lineptr, size_t *n, FILE *stream); ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
需要单独define _GNU_SOURCE,也可以在makefile中来写,这样就比较规整。
CFLAGS+=-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall
getline函数的例子,getline.c
从流中取任意数据,如何实现?标准函数貌似没办法实现? getline函数,自己实现以下试试。