2.C标准I/O

2 C 标准I/O

2.1 文件指针

  • 标准I/O并不直接操作文件描述符,而是通过文件指针(file pointer)。文件指针映射到一个文件描述符。文件指针类型为FILE,定义在头文件<stdio.h>
  • 在标准I/O中,一个打开的文件叫做“流”(stream)。
  • 标准输入 输出 错误的流通过预定义文件指针 stdinstdoutstderr加以引用

2.2 打开文件

  • 文件通过 fopen()打开以提供读写操作:打开文件并为它关联一个新的流
#include <stdio.h>
FILE* fopen(const char * path, const char * mode);
                                    //成功返回文件指针,否则返回NULL
  • mode
mode 说明
r 打开文件用来读,流定位在文件开始处
r+ 打开文件用来读写,流定位在文件开始处
w 打开文件用来写,如果文件存在,文件会被清空。如果不存在,会被创建。流定位在文件开始。
a d打开文件用来追加模式的写入。如果文件不存在它会被创建。流被设置在文件的末尾,所有写入都会接在文件后。
a+ 打开文件用来追加模式的读写。如果文件不存在它会被创建。流被设置在文件的末尾,所有写入都会接在文件后。
b 表示二进制形式,这个值在linux下被忽略,因为文本文件和二进制文件都一视同仁
  • 通过文件描述符打开文件
  • 函数fdopen()将一个已经打开的文件描述符转换成流
#include <stdio.h>
FILE* fdopen(int fd, const char * mode);
  • 可能模式与上面一样,但必须和原来打开文件描述符的模式匹配。可以指定w,w+,但是他们不会截断文件。流的位置设置在文件描述符指向的文件位置。可以但不要在打开流的情况下直接操作描述符。关闭流也会关闭描述符。

2.3 关闭流

  • fclose()函数关闭一个给定的流
#include <stdio.h>
int fclose(FILE * stream);
                        //成功返回0,失败返回EOF(-1),设置errno
  • fcloseall()关闭所有和当前程序关联的流,包括标准输入,输出,错误
#include <stdio.h>
int fcloseall(void);
                //该函数始终返回0;该函数是linux特有的

3.3 从流中读取数据

  • 单字节读取
#include <stdio.h>
int fgetc(FILE * stream);
    //读取一个字符,并把该无符号字符强转成int返回。文件结尾,错误都返回EOF(-1)
  • 把字符放回流中
  • 允许你偷窥流,如果不需要,可以把它放回
#include <stdio.h>
int ungetc(int c,FILE * stream);
    //把c强转为无符号字符,放回流中,成功返回c,否则返回EOF
    //如果使用了一次定位函数,所有推回的字符被丢弃
  • 按行读取
#include <stdio.h>
char * fgets(char *str, int size, FILE * stream);
    //从流中读取最多size-1个字节数据,遇到文件尾或换行时读入结束,如果读到‘\n’
    //也放入str,最后把空字符'\0'放到str结尾。成功返回str,失败返回NULL
  • 读取二进制文件
#include <stdio.h>
size_t fread(void *buf, size_t size, size_t nr, FILE* stream);
    //从流中读取nr个数据,每个数据大小为size,放入buf中
    //实际读入的个数被返回(注意不是字节数)
    //返回小于nr的值时读取失败或文件结束,用ferror()和feof()判断

3.4 向流中写数据

#include <stdio.h>
//写入单个字符
int fput(int c, FILE * stream);
    //成功返回c,否则返回EOF
//写入字符串
int fputs(const char *str, FILE *stream);
    //将str中'\0'前部分写入stream指向的流中,成功返回非负整数,失败EOF
//写入二进制数据
size_t fwrite(void *buf, size_t size, size_t nr, FILE *stream);
    //把buf指向的nr个元素(每个元素大小为size)写入流,返回实际写入个数,小于nr出错

3.5 定位/清洗流

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
    //成功返回0,清空文件结束标志,取消ungetc()操作,错误返回-1
  • SEEK_SET ,将该文件偏移量设置为距文件开始处offset个字节
  • SEEK_CUR ,将该文件偏移量设置为当前值+offsetoffset可正可负
  • SEEK_END ,将该文件偏移量设置为文件长度+offsetoffset可正可负
//将流位置设置到pos处
int fsetpos(FILE *stream, const fpos_t *pos);
    //成功返回0,否则返回-1
//将当前位置填入pos
int fegtpos(FILE *stream, fpos_t *pos);

void rewind(FILE *stream);
    //等于 fseek(stream,0,SEEK_SET); 位置重置为初始位置

//返回当前流位置
long fetll(FILE *stream);
    //错误返回-1

//清洗一个流,流中数据立即刷新到内核中
int fflush(FILE *stream);

3.6 错误和文件结束

#include <stdio.h>
//测试流上是否设置了错误标志
int ferror(FILE *stream);
    //如果有错误标记,返回非0,否则返回0
//测试文件结尾标记是否被设置
int feof(FILE *stream);
    //如果有文件结束标记,返回非0,否则返回0
//清空错误和结尾标记
void cleareer(FILE *stream);

3.7 控制缓冲和关联描述符

  • 提供三种用户缓冲,不缓冲,行缓冲(标准输出默认),块缓冲(文件操作默认)
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
    //必须在流打开后,任何操作之前调用
    //成功返回0,否则返回非0
  • mode

    • _IONBF 无缓冲
    • _IOLBF 行缓冲
    • _IOFBUF 块缓冲
  • _IONBF情况下buf和size被忽略

  • buf可以指向一个size字节大小的缓冲空间,如果buf为NULL,则由glibc自动分配

  • 获得关联文件的描述符

#include <stdio.h>
int fileno(FILE *stream);
    //成功返回和流关联的文件描述符,否则返回-1

3.8 线程安全

  • 单个I/O操作是原子的,但有时需要加锁一组操作

  • 又时有不需要单个I/O的锁机制

  • 手动文件加锁

#include <stdio.h>
void flockfile(FILE *stream);
    //等待流解锁 并 获得锁 然后返回
vodi funlockfile(FILE *stream); //解锁

//非阻塞加锁版本
int ftrylockfile(FILE *stream);
    //没有拿到锁返回非零,拿到了返回0
  • 不加锁的流操作,linux提供一系列函数
#include <stdio.h>
int getc_unlocked(FILE *stream);
int getchar_unlocked(void);
int putc_unlocked(int c, FILE *stream);
int putchar_unlocked(int c);

void clearerr_unlocked(FILE *stream);
int feof_unlocked(FILE *stream);
int ferror_unlocked(FILE *stream);
int fileno_unlocked(FILE *stream);
int fflush_unlocked(FILE *stream);
int fgetc_unlocked(FILE *stream);
int fputc_unlocked(int c, FILE *stream);
size_t fread_unlocked(void *ptr, size_t size, size_t n,
                      FILE *stream);
size_t fwrite_unlocked(const void *ptr, size_t size, size_t n,
                      FILE *stream);

char *fgets_unlocked(char *s, int n, FILE *stream);
int fputs_unlocked(const char *s, FILE *stream);
...
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容