【1】i/o
本质就是输入输出函数,也是读写函数
【2】系统调用和库函数
系统调用:
使用函数控制linux内核,linux内核来操作硬件
库函数:
库函数的本质还是系统调用,只不过需要在内存当中开辟一块空间(缓冲区),从而减少系统调用的次数
【3】io分类
文件io:
就是系统调用,例如:open、read、write
移植性比较差
标准io:
就是库函数,例如:printf、scanf
移植性比较好
【4】标准I/O
(1)概念
不仅在UNIX系统,在很多操作系统上都实现了标准I/O库,标准I/O库由ANSI C标准说明。标准I/O库处理很多细节,如缓存分配、以优化长度执行I/O等,这样使用户不必关心如何选择合适的块长度。标准I/O在系统调用函数基础上构造的,它便于用户使用。标准I/O库及其头文件stdio.h为底层I/O系统调用提供了一个通用的接口。标准io本质还是系统调用,只不多在执行系统调用前,在内存当中开辟一块区域(缓冲区)用于减少系统调用的次数。
(2)缓冲区的分类
机制:将要操作的数据先放在缓冲区中,如果刷新缓冲区,就立即执行系统调用, 如果没有缓冲区,数据会一直存储在缓冲区中。
①行缓冲:对于终端操作采用的缓冲区
缓存区大小: 1024字节(1K)
刷新缓存 :程序正常结束、缓存区满、 ’
’ 、使用fflush函数
②全缓冲:对于文件操作采用的缓冲区
缓存区大小:4096字节(4K)
刷新缓存 :程序正常结束、缓存区满、使用fflush函数
③无缓冲:对于终端操作采用的缓冲区
#include
int main(int argc, const char *argv[])
{
//标准io在执行的时候都需要刷新缓冲区,如果不刷新没有办法执行相应操作
//printf("hello world");
//如何刷新缓冲区
//方法1:使用
//printf("hello world
");
//方法2:当前程序正常结束
//printf("hello world");
//return 0;
//方法3:使用fflush( )函数
//printf("hello world");
//fflush(stdout);
//方法4:当缓冲区满的时候,可以刷新缓冲区
int i;
for(i = 1; i <= 300; i++)
{
printf("%03d ", i);
}
while(1)
;
return 0;
}
(3)ctags的创建和使用
ctags是在指定目录文件里面建立索引文件,用于查找指定内容(宏定义、重命名、结构体)的具体位置。
① 创建索引文件
在/usr/include目录里面执行sudo ctags -R,会在当前目录下生成tags的索引文件。
测试:vim -t FILE
②将当前索引文件设置为全局
在家目录下的.vimrc文件里面添加set tags+=/usr/include/tags
③ 基本操作指令
vim -t *** 查找对应内容的位置
输入编号可以执行到达执行数据的文件的位置,如果编号较多,可以按
两下esc再输入编号
ctrl+] 追代码
ctrl+t 返回上一级
(4)文件指针(流指针)
FILE结构体:
每一个使用标准io操作的文件都会通过一个结构体来标识当前文件的信息,
这个结构体的类型名为FILE,标准io操作文件是通过当前结构体的指针变量
来操作的,称之为流或者流指针,流就是用来标识和操作文件的。
typedef struct _IO_FILE FILE;
FILE * 流指针的类型
当进程创建或者开启的时候,会先创建三个流指针
stdin 标准输入 从终端输入
stdout 标准输出 从终端输出
stderr 标准出错 从终端出错输出
(5)库函数
①fopen() 打开或者创建文件
#include
FILE *fopen(const char *path, const char *mode);
功能:打开或者创建一个文件,得到一个流指针
参数:
path:文件名,可以添加路径,默认不添加为当前路径
mode:文件的访问权限
r 以只读的方式打开文件,定位到文件起始位置
r+ 以读写的方式打开文件,定位到文件起始位置
w 以只写的方式打开文件,如果文件不存在则创建,如果存在则清空,定位到文件起始位置
w+ 以读写的方式打开文件,如果文件不存在则创建,如果存在则清空,定位到文件起始位置
a 以只写的方式打开文件,如果文件不存在则创建,如果存在则追加,定位到文件末尾位置
a+ 以读写的方式打开文件,如果文件不存在则创建,如果存在则追加,定位到文件末尾位置
返回值:
成功:流指针
失败:NULL
include
#include
int main(int argc, const char *argv[])
{
//使用fopen打开或者创建文件
FILE *fp;
if((fp = fopen("file.txt", "r")) == NULL)
{
//errno:是一个变量,用于获取函数调用错误后的错误码
printf("errno = %d
", errno);
//使用perror函数打印函数调用失败的错误信息
perror("fail to fopen");
return -1;
}
//使用fclose关闭流指针
fclose(fp);
return 0;
}
②perror( ) 输出函数调用失败的错误信息
#include
void perror(const char *s);
功能:输出函数调用失败的错误信息
参数:
s:提示字符串
返回值:无
errno 在errno.h定义的全局变量,用于获取函数调用错误后的错误码,可以在errno.h里面找到对用错误码的错误信息
③fclose( ) 关闭一个流指针
#include
int fclose(FILE *fp);
功能:关闭一个流指针
参数:
fp:指定的流
返回值:
成功:0
失败:EOF
④fprintf( ) 向一个文件写数据
#include
int fprintf(FILE *restrict stream, const char *restrict format, ...);
功能:向一个文件写数据
参数:
stream:指定的文件的流指针
format:同printf的参数
返回值:
成功:输出的字符的个数
失败:-1
#include
int main(int argc, const char *argv[])
{
//向终端输出数据
fprintf(stdout, "hello world
");
char name[] = "zhangsan";
fprintf(stdout, "My name is %s
", name);
//向文件写入数据
FILE *fp;
if((fp = fopen("file.txt", "w")) == NULL)
{
perror("fail to fopen");
return -1;
}
fprintf(fp, "hello world
");
char n[] = "zhangsan";
fprintf(fp, "My name is %s
", n);
return 0;
}
⑤freopen( ) 对于一个已有的流进行重定向
FILE *freopen(const char *restrict pathname,
const char *restrict type, FILE* restrict fp)
#include
int main(int argc, const char *argv[])
{
printf("nihao beijing
");
FILE *fp;
//将标准输出的数据重定向写入一个文件里面
if((fp = freopen("file.txt", "a", stdout)) == NULL)
{
perror("fail to freopen");
return -1;
}
printf("nihao beijing
");
return 0;
}
⑥字符的读写函数
1 – fgetc( )
#include
int fgetc(FILE *stream);
功能:从一个文件读取一个字符
参数:
stream:指定的文件的流指针
返回值:
成功:读取到的字符的ascii码值
失败:EOF
如果读取到文件的末尾,会返回EOF
#include
int main(int argc, const char *argv[])
{
//从终端获取一个字符
#if 0
int c;
//c = getchar();
c = fgetc(stdin);
printf("[%c] -- %d
", c, c);
#endif
if(argc < 2)
{
fprintf(stderr, "Usage: %s filename
", argv[0]);
return 1;
}
//从文件里面读取一个字符
FILE *fp;
if((fp = fopen(argv[1], "r")) == NULL)
{
perror("fail to fopen");
return -1;
}
#if 0
int c = fgetc(fp);
printf("[%c] -- %d
", c, c);
c = fgetc(fp);
printf("[%c] -- %d
", c, c);
c = fgetc(fp);
printf("[%c] -- %d
", c, c);
#endif
//文件的每一行的结尾处都有一个换行符
//fgetc可以读取到换行符
int c;
while((c = fgetc(fp)) != EOF)
{
printf("[%c] -- %d
", c, c);
}
fclose(fp);
return 0;
}
2 – fputc( )
#include
int fputc(int c, FILE *stream);
功能:向一个文件写入一个字节的数据
参数:
c:要写入的字符
stream:指定的文件的流指针
返回值:
成功:写入的字符
失败:EOF
#include
int main(int argc, const char *argv[])
{
//向终端写入一个字符
#if 0
putchar('a');
putchar(122);
char c = 'W';
putchar(c);
putchar(10);
#endif
#if 0
fputc('T', stdout);
fputc(100, stdout);
char a = 'U';
fputc(a, stdout);
fputc(10, stdout);
#endif
//向文件写入一个字符
FILE *fp;
if((fp = fopen("file.txt", "r+")) == NULL)
{
perror("fail to fopen");
return -1;
}
fputc('h', fp);
fputc('e', fp);
fputc('l', fp);
fputc('l', fp);
fputc('o', fp);
fputc('N', fp);
fputc('O', fp);
//当文件写完数据后,此时的文件的偏移量是文件的末尾处,所以如果读取数据的话读取不到
#if 0
int c;
while((c = fgetc(fp)) != EOF)
{
printf("%c - ", c);
}
putchar(10);
#endif
fclose(fp);
return 0;
}
⑦ 字符串读写函数
1 – fgets( )
#include
char *fgets(char *restrict s, int n, FILE *restrict stream);
功能:从一个文件读取一串字符
参数:
s:保存读取的数据
n:读取的字节数
stream:指定的文件的流指针
返回值:
成功:读取的数据
失败:NULL
当读取到文件末尾时,fgets返回NULL
#include
#include
int main(int argc, const char *argv[])
{
//从终端读取数据
#if 0
char s[32] = {};
//gets(s);
//fgets从终端读取字符串时,
//如果读取的内容小于第二个参数值,则会将换行符也读到数组里面
//如果读取的内容大于第二个参数值,则只会获取到第二个参数-1个字节,最后一个位置补