IO函数-1

1.选择标准库还是linux系统函数库

大部分情况下选择标准库,以支持跨平台的需求;

2.常见IO函数

2.1 fopen()函数

#include<stdio.h>
FILE *fopen(const char *path,const char*mode)

参数:
path:
是一个字符串,包含欲打开的文件路径及文件名
mode:
r:只读方式打开,将文件指针指向文件头。
r+:读写方式打开,将文件指针指向文件头。
w:写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
w+:读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
a:写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
a+:读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。

返回值:
成功:返回一个指向FILE结构的指针
失败:返回NULL,并且会设置相应的errno

2.2 fclose()函数

#include <stdio.h>
int fclose( FILE *stream );

返回值:
对于输出流,fclose函数会在文件关闭前刷新缓冲区,如果它执行成功,fclose返回零值

注意点:
fclose函数执行后,就可以把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。

2.3 fgetc()函数

#include<stdio.h>
int fgetc (FILE *fp);

参数:
fp:

需要读取的文件指针

返回值:
返回值类型为int,不是char。
读取成功时返回读取到的字符,读取到文件末尾或读取失败时返回EOF。

工作机制:
在文件内部有一个位置指针,用来指向当前读写到的位置,也就是读写到第几个字节。在文件打开时,该指针总是指向文件的第一个字节。使用 fgetc() 函数后,该指针会向后移动一个字节,所以可以连续多次使用 fgetc() 读取多个字符。

注意:
这个文件内部的位置指针与C语言中的指针不是一回事。位置指针仅仅是一个标志,表示文件读写到的位置,也就是读写到第几个字节,它不表示地址。文件每读写一次,位置指针就会移动一次,它不需要你在程序中定义和赋值,而是由系统自动设置,对用户是隐藏的。

补充:
1.EOF 是 end of file 的缩写,表示文件末尾,是在 stdio.h 中定义的宏,它的值是一个负数,往往是 -1。fgetc() 的返回值类型之所以为 int,就是为了容纳这个负数(char不能是负数)
EOF 不绝对是 -1,也可以是其他负数,这要看编译器的实现。

2.返回EOF时,如何区分是读取到文件末尾还是读取失败?
通过 feof() 或者ferror()进行状态判断。
feof() 函数

int feof ( FILE * fp );

用来判断文件内部指针是否指向了文件末尾,当指向文件末尾时返回非零值,否则返回零值。

ferror() 函数

int ferror ( FILE *fp );

出错时返回非零值,否则返回零值。

#include<stdio.h>

int main()
{
    FILE *fp;
    int ch;
  
    //如果文件不存在,给出提示并退出
    if( (fp=fopen("D:\\demo.txt","rt")) == NULL ){
        puts("Fail to open file!");
        exit(0);
    }

    //每次读取一个字节,直到读取完毕
    while( (ch=fgetc(fp)) != EOF ){
        putchar(ch);
    }
    putchar('\n');  //输出换行符

    if(ferror(fp)){
        puts("读取出错");
    }else{
        puts("读取成功");
    }

    fclose(fp);
    return 0;
}

2.4 fputc()函数

#incldue<stdio.h>
int fputc ( int ch, FILE *fp );

参数:
ch :
为要写入的字符
fp :
要写入的文件指针

返回值:
返回值类型为 int
写入成功时返回写入的字符,失败时返回 EOF

说明:
1.被写入的文件可以用写、读写、追加方式打开,用写或读写方式打开一个已存在的文件时将清除原有的文件内容,并将写入的字符放在文件开头。如需保留原有文件内容,并把写入的字符放在文件末尾,就必须以追加方式打开文件。不管以何种方式打开,被写入的文件若不存在时则创建该文件。

2.每写入一个字符,文件内部位置指针向后移动一个字节。

2.5 fgets()函数

#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);

功能:
从 stream 流中读取 size -1个字符存储到字符指针变量 s 所指向的内存空间,在读入的最后一个字符后加上串结束标志’/0’。
参数:
s :
要保存到的内存空间的首地址,可以是字符数组名,也可以是指向字符数组的字符指针变量名
size:
从文件中读出的字符串不超过 size-1个字符
stream:
从何种流中读取,可以是标准输入流 stdin,也可以是文件流。

返回值
如果成功,该函数返回相同的 s 参数;
如果到达文件末尾或者没有读取到任何字符,s的内容保持不变,并返回一个空指针;
如果发生错误,返回一个空指针。

文件内容指针移动问题:
如果一行的字符串没读取完会,下一次会接着上一次读取,文件内容指针会做相应移动;
如果读完了,文件内容指针会指向下一行开头,直接从下一行开头开始读取。

2.6 fputs()函数

#include<stdio.h>
int fputs(const char *str, FILE *stream)

功能
把字符串str写入到指定的流 stream 中,但不包括空字符。

参数
str:
这是一个数组,包含了要写入的以空字符终止的字符序列。
stream:
这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。

返回值:
成功返回一个非负值,如果发生错误则返回 EOF。

2.6 feek()函数

#include<stdio.h>
int fseek( FILE *stream, long offset, int whence);

功能
对流的文件指针重定位;

参数
stream:
要重定位的流
offset:
相对于whence的偏移量,整数表示正向偏移,负数表示负向偏移
whence:
要偏移的起始位置。SEEK_SET: 文件开头;SEEK_CUR: 当前位置;SEEK_END: 文件结尾,也可以依次用0,1和2表示。

返回值
如果执行成功,stream将指向以whence为基准,偏移offset(指针偏移量)个字节的位置,函数返回0。如果执行失败(比如offset取值大于等于210241024*1024,即long的正数范围2G),则不改变stream指向的位置,函数返回一个非0值。

举例
fseek(fp,100L,0); 把fp指针移动到离文件开头100字节处;
fseek(fp,100L,1); 把fp指针移动到离文件当前位置100字节处;
fseek(fp,-100L,2); 把fp指针退回到离文件结尾100字节处、

stdio: FILE类型贯穿始终
fread(); 
fwrite();

fprintf(); //常用于输出重定向
sprintf(); //可以当作atoi()的反向函数 
snprinf(); //相比sprintf(),可以防止写入越界
scanf();

//文件位置指针
fseek();
ftell();
rewind();

fflush();

3.man命令使用

man 1 + 命令:基本linux命令
man 2 + 命令:系统调用函数
man 3 + 命令: 标准库函数
man 7 + 命令:讲机制
eg: man 7 TCP
	man 7 epoll
	man 7 socket

4.fopen()函数详解

SYNOPSIS:
FILE *fopen(const char *path, const char *mode);//常量指针,path和mode在函数体内均不可改变
DESCRIPTION

在这里插入图片描述

fopen()返回值FILE*为结构体,指向的内容存放在堆上。需要与fclose()配对使用,以免造成内存泄漏;

打开模式:
在这里插入图片描述
w:无则创建,有则清空
两种特殊打开模式:r and r+
打开文件,如果不存在,则当前调用结束,返回值出错;

linux下rb可以忽略b,见下图

在这里插入图片描述

4.1 errno详解

errno:宏定义的全局变量
查看errno编码表方式: 
vim /usr/include/asm-generic/errno-base.h //编号1~34
vim /usr/include/asm-generic/errno.h //编号35~133

在这里插入图片描述
如何测试errno为宏定义,而不是int类型?

编写测试文件,errnotest.c

#include <errno.h>

void main()
{
	int a = 0;
	errno;
}
gcc -E errnotest.c, 预处理#的内容

结果如下:
在这里插入图片描述
int a没有展开,errno已经按照宏定义展开

5.fread()与fwrite()

在这里插入图片描述
从stream中按照固定size读取numeb次,写入到ptr指向的地址中去。fwrite相反。
用于成块读取数据
缺点之一:不能检查写入或读取到的地址边界大小;
缺点之二:返回值问题,如果size不为1,可能不能识别小于size的具体个数;
在这里插入图片描述

1-> 数据量足够
2-> 数据量只有5个字节

fread(buf, 1, 10, fp);
1->  读取次数10  -> 读取量可以计算出为10字节
2->  5 -> 5字节
fread(buf, 10, 1, fp);
1->	  1 -> 10字节
2->   0 -> 计算不出有多少字节待读取

建议:
fread(buf, 1, nemb, fp),进行单字节读取,当做fgetc()使用;
fwrite(buf, 1, nemb, fp),单字节写入,当做fputc()使用;

diff A B //比较A B两文件文本内容是否相同

6.文件位置指针函数

//文件位置指针
fseek();//SEEK_SET 文件开头 SEEK_CUR 文件当前位置 SEEK_END 文件末尾
rewind(); <=> (void)fseek(FILE* stream, 0L, SEEK_SET);
把文件位置指针定位到文件开头
在这里插入图片描述
fseek():如果执行成功,stream将指向以whence为基准,偏移offset(指针偏移量)个字节的位置,函数返回0。如果执行失败(比如offset取值大于等于210241024*1024,即long的正数范围2G),则不改变stream指向的位置,函数返回一个非0值。
ftell():用于得到文件位置指针stream当前位置相对于文件首的偏移字节数。

long型范围2G-1~2G+·1
如果fseek()与ftell()结合使用,则最多能够处理2G大小的文件,因为ftell()返回值需要为+;

空洞文件: 刚开始下载文件,计算要下载的文件大小,然后通过fseek()生成一个和下载文件大小一样的空洞文件,以提前占用磁盘的内存空间;空洞文件内容全部是\0
假如要下载文件大小为2G,则fseek(fp, 2G, SEEK_END);
然后对下载文件切片,使用多线程分别下载切片的部分;

小结

1.缓冲区的作用:大多数情况下是好事,合并系统调用
分类:
行缓冲:换行时候刷新,满了的时候刷新,强制刷新(标准输出是行缓冲,因为是终端设备)
全缓冲:满了的时候刷新,强制刷新(默认,只要不是终端设备)
无缓冲:如stderr,需要立即输出的内容
切换缓冲类型函数:setvbuf();
2.如果一个函数的返回值是指针,如fopen(),且有逆函数(如fopen()的逆函数为fclose()),则
函数返回的指针一般放在上面。如果没有互逆操作,有可能在堆、栈或者静态区,
需要写函数验证;
3.不更改当前环境下,一个进程打开时,默认自动打开三个流,stdin, stdout, stderr
查看当前进程最多产生文件数

ulimit -a

4.宏会占用编译时间,不占用进程系统调用时间;
函数调用相反;内核更多通过宏来节省时间;应用程序处于稳定、可靠性,更多还是函数调用;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值