嵌入式Linux应用编程之I/O进程(上)

2019-07-13 02:03发布

【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个字节,最后一个位置补