当前位置: 首页 > news >正文

10.Linux笔记:应用编程开始、文件IO

1.应用编程概念

应用编程:把前人写好的模块化的程序或函数直接拿来用,叫应用编程。

应用编程时,拿到一个写好的接口函数,首先要想的是怎么用好它,不是非要研究怎么创造它。

统一标准、统一接口

分工的任务合在一起形成一个产品,需要标准的接口才能实现成功合并

默认有一套标准的接口去守它的一个守则。可能是公司写好的,可能是行业写好的。

应用开发时,看到别人写好的(接口、函数、工具)时,看到它的(返回值、参数)要能知道它干什么用的,大致结构要能猜到。

什么是接口?

接口是规范、是协议,不包含具体怎么实现,不包含具体的代码。

接口函数:在接口的规范之下,实现对应功能的具体代码。

什么是例程?
什么是api?

api只是一个规则,只是一个声明,它不占用内存,也不运行任何代码。

api的核心三要素:1可以为你实现的功能有哪些、2规定输入内容的格式、3规定输出内容的格式。

api本身没有具体实现功能的函数。流程是如下:

1.api提供一个菜单,上面有可选的功能或需求。

2.用户提出需求给api,api将需求转交给对应的函数

3.函数的返回值直接交给用户,回来的时候就不经过api了。

系统调用是api,库函数是api。api是一组预定义的规则和接口,让程序之间可以互相调用功能。

系统调用:是内核对外的api声明,里面有内核的功能菜单,然后具体干活的是内核。

库函数:库函数的声明是api,具体干活的是:库自己的代码(在用户态执行)。它可能再调用系统调用(让内核干活),也可能完全自己干完。

如果一个人提供api给你:需要给你三样东西:头文件、实现代码(或者源码)、接口文档。

接口文档(每个函数是干什么的、参数分别代表什么、返回值如何判断成功/失败、使用注意事项(比如是否需要加锁、是否可重入等))

用好man手册:

遇到没用过的接口函数,要先去查man手册,翻译、总结,了解用法再去使用,不要着急写代码,用错了事倍功半。

2.文件与IO

一切皆文件

linux下一切皆文件,鼠标键盘插上去,系统里多出一个文件。

系统调用(api)

系统调用介于内核层和用户层之间,是一个交流窗口。

shell命令、用户程序他们两个平级,要想访问内核,都会先通过系统调用。(系统调用是众多api的一种)。系统调用会先把用户层发来的服务请求进行分类,再交付给内核。

shell和用户程序虽然是平级,但是,shell一直存在,shell负责把用户程序领到系统调用那里。

系统调用里的IO都是文件IO,linux下一切皆文件。

什么是IO:

IO设备:输入输出数据的硬件设备。

IO接口函数:将IO设备提供需求的数据,通过函数来实现对应功能。不同类型的功能,有对应的专用协议。

对某一类的功能或应用(比如嵌入式IO的功能或应用),在写对应的IO接口函数时,有专门或常规的一套接口形式的范本或协议。这样就具备通用性,可以不同场景广泛应用。

IO接口:是IO设备设备 和 系统(通过IO接口函数)的桥梁。

C库函数(api)的作用:

库函数是提前写好的,封装好的函数,很标准,bug很少。

不同内核,使用不同版本的系统调用(api),这时,在调用时可能有不方便。于是,将一部分系统调用封装、优化成更便利的C库函数(设计另一个更便利、安全的api)。

库函数有的会调用系统调用,有的不会。

C库函数里有很多接口函数,不只IO接口函数(文件IO、标准IO),还有其他接口。

C库函数里90%是接口函数,供用户调用。

系统调用,让内核来干活:通常是针对硬件或底层操作。库函数针对应用层来操作。

一些IO接口的实现,直接与硬件设备、系统内核密切相关,例如系统调用函数;

一些IO接口的实现侧重屏蔽底层差异,提供兼容性更广的应用编程的数据交换方法(接口),例如C库函数。

总结:

系统调用是API,库函数也是API。

库函数封装了系统调用的一部分接口函数的声明:如:库函数里的标准IO就是封装了系统调用里的文件IO(额外加上缓存)。所以,标准IO使用时,库函数会内部调用系统调用里的文件IO,来访问内核里的文件IO函数。

系统调用是内核提供的 API,库函数是用户态提供的 API。部分库函数(如标准 I/O)封装了系统调用,以增加缓存等高级功能。标准 I/O 函数在需要实际读写数据时,会调用相应的系统调用进入内核。

3.文件IO基础

文件IO 系统调用内核里的struct file ,然后返回int类型的fd值。在应用层对fd进行操作,fd是文件描述符。

文件描述符

英文缩写fd(file descriptor),范围0-1023。文件IO操作通过fd来完成。

0为标准输入,1为标准输出,2为标准出错。所以,文件IO操作fd的范围是3~1023

man手册

终端输入:

man man 查看man手册

man 1 查看可执行文件和shell

man 2 查看系统调用 如: man 2 open

man 3 查看库函数(库调用)

4.文件的打开与关闭

open接口函数:

终端:man 2 open

头文件、函数原型、描述

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags,mode_t mode);

close接口函数:

man 2 close

#include <unistd.h>

int close(int fd); 关闭成功返回值0,关闭失败返回值1

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> int main(int argc, const char *argv[]) { int fd = -1; #if 1 if((fd = open("helloworld.txt",O_RDONLY)) < 0) { printf("open error!\n"); return -1; } printf("open success! fd :%d\n",fd); #else if((fd = open("4.txt",(O_RDONLY|O_CREAT|O_EXCL),0664)) < 0) { printf("open error!\n"); return -1; } printf("open success! fd :%d\n",fd); #endif if(!close(fd)) printf("close success!\n"); return 0; }
umask设定权限
#include <sys/types.h>
#include <sys/stat.h>

ulimit获取文件打开范围

5.文件的读写

read接口函数

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #define N 20 int main(int argc, const char *argv[]) { int fd = -1,n = 0,total = 0; char buf[N] = {0}; if(argc < 2){return -1; } //if((fd = open("helloworld.txt",O_RDONLY)) == EOF ) if((fd = open(argv[1],O_RDONLY)) == EOF ) { printf("open error!\n"); return -1; } printf("open success! fd :%d\n",fd); while((n = read(fd,buf,N)) > 0){ 读一次,返回正数证明后面还有内容,光标此时在最后 printf("%s",buf); total += n; } printf("read characters: %d\n",total); printf("finished reading \n"); if(!close(fd)) printf("close success!\n"); return 0; }

write接口函数

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <string.h> #define N 20 int main(int argc, const char *argv[]) { int fd = -1,n = 0; char buf1[N] = {0}; char buf2[N] = "hello wolrd!!!"; if(argc < 2){return -1; } #if 0 if((fd = open(argv[1],O_RDWR)) == EOF ) { printf("open error!\n"); return -1; } printf("open success! fd :%d\n",fd); #elif 0 if((fd = open(argv[1],O_RDONLY)) == EOF ) { printf("open error!\n"); return -1; } printf("open success! fd :%d\n",fd); #else if((fd = open(argv[1],O_WRONLY)) == EOF ) { printf("open error!\n"); return -1; } printf("open success! fd :%d\n",fd); #endif //读操作 if(( n = read(fd,buf1,N)) < 0){ printf("read error"); return -1; } printf("read success\n"); printf("read characters: %s\n",buf1); //写操作 do{ n = write(fd,buf2,strlen(buf2)); }while(n < 0); printf("write characters :%d\n",n); printf("write finished\n"); if(!close(fd)) printf("close success!\n"); return 0; }

6.文件IO:定位文件与访问权限修改

lseek接口函数

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #define N 20 #include <string.h> int main(int argc, const char *argv[]) { int fd = -1; int ret = 0; char buf[N] = {0}; if((fd = open("test.txt",O_RDWR)) < 0) { printf("open error!\n"); return -1; } printf("open success! fd :%d\n",fd); ret = lseek(fd,0,SEEK_CUR); printf("%u\n",ret); read(fd,buf,10); printf("%s\n",buf); ret = lseek(fd,0,SEEK_CUR); printf("%u\n",ret); lseek(fd,0,SEEK_END); write(fd,"aaa", strlen("aaa")); ret = lseek(fd,0,SEEK_CUR); printf("%u\n",ret); ret = lseek(fd,0,SEEK_SET); printf("%u\n",ret); bzero(buf,sizeof(buf)); while(read(fd,buf,sizeof(buf)) > 0){ printf("%s",buf); } putchar('\n'); printf("read end\n"); if(!close(fd)) printf("close success!\n"); return 0; }

bzero函数,属于库函数里 man 3,作用:清除buf里的内容

chmod/fchmod接口函数

被改成只写,所以后面打开文件以读写权限时会报错

open实在文件原本权限基础上打开,不能超越文件原本权限。

7.标准IO基础

标准IO是在封装系统调用文件IO的基础上,加了缓存,减少了系统调用的次数,降低了与硬件内核之间的硬耦合。

文件IO用文件描述符fd来存文件信息。

标准IO用结构体来存文件信息,这个结构体叫流(FILE),同时加一个缓存区。

无缓存:

行缓存:

标准IO全缓存:

读:标准IO读缓存区放满了,才会刷新,去调用系统调用文件IO的read接口函数

写:标准IO写缓存区放满了,才会刷新,去调用系统调用文件IO的write接口函数

两个标准IO函数:

fopen:打开一个文件,并生成FILE结构

#include <stdio.h> #include <unistd.h> int main(int argc, const char *argv[]) { FILE *fp = fopen("a.txt","a+"); //fprintf(fp,"a"); printf("%lu\n",fp->_IO_buf_end - fp->_IO_buf_base); int i = 0; do{ fprintf(fp,"a"); i++; }while(i<4098); printf("%lu",fp->_IO_write_ptr - fp->_IO_write_base); sleep(5); return 0; }
setbuf修改缓存类型函数

#include <stdio.h> #include <unistd.h> int main(int argc, const char *argv[]) { printf("a"); sleep(5); setbuf(stdout,NULL); printf("b"); sleep(5); return 0; }

8.标准IO:文件打开、关闭、错误处理

fopen接口函数

#include <stdio.h> int main(int argc, const char *argv[]) { FILE * fp = NULL; if((fp = fopen("test.txt","a+")) == NULL){ printf("fopen error\n"); return -1; } printf("fopen success\n"); fclose(fp); return 0; }
fclose接口函数

errno、perror、strerror错误信息处理函数

#include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> int main(int argc, const char *argv[]) { FILE * fp = NULL; #if 0 if( (fp = fopen("test.txt","r")) == NULL ){ printf("errno:%d\n",errno); perror("fopen:"); return -1; } #else if( (fp = fopen("test.txt","r")) == NULL ){ printf("errno:%d\n",errno); printf("fopen:%s\n",strerror(errno)); return -1; } #endif printf("errno:%d\n",errno); perror("perror:"); sleep(3); fclose(fp); return 0; }

9.标准IO操作:字符行、读写

fgetc、getc、getchar字符输入接口函数

#include <stdio.h> int main(int argc, const char *argv[]) { int c; FILE *fp = NULL; if((fp = fopen("test.txt","r+")) == NULL ){ perror("fopen"); return -1; } printf("fopen success\n"); while(1){ #if 0 if( (c = fgetc(fp)) == EOF ){ perror("fgetc"); break; } #else if( (c = getc(fp)) == EOF ){ perror("getc"); break; } #endif printf("%c",(char)c); } fclose(fp); return 0; }
fputc、putc、putchar字符输出接口函数

#include <stdio.h> int main(int argc, const char *argv[]) { int c; FILE *fp = NULL; if((fp = fopen("test.txt","a+")) == NULL ){ perror("fopen"); return -1; } printf("fopen success\n"); #if 1 if( (c = fputc('a',fp)) == EOF ){ perror("fputc"); return -1; } #elif 0 if( (c = putc('a',fp)) == EOF ){ perror("putc"); return -1; } #else putchar('b'); #endif printf("c = %c\n",c); fclose(fp); return 0; }
实践:字符读写复制文件
#include <stdio.h> int main(int argc, const char *argv[]) { FILE * fp_a = NULL,* fp_b = NULL; int c = 0; if(argc < 3 ){ printf("Usage: %s <be copied file> <copied file>\n",argv[0]); return -1; } if((fp_a = fopen(argv[1],"r+")) == NULL){ perror("be copied file fopen"); return -1; } if((fp_b = fopen(argv[2],"w+")) == NULL){ perror("copied file fopen"); fclose(fp_a); return -1; } printf("fopen files ok\n"); do{ if((c = fgetc(fp_a)) == EOF){ perror("fgetc"); break; } if((fputc(c,fp_b)) == EOF){ perror("fputc"); break; } }while(1); fclose(fp_a); fclose(fp_b); return 0; }
fgets行输入接口函数:

#include <stdio.h> #define N 32 #define M 6 int main(int argc, const char *argv[]) { FILE * fp = NULL; char buf[M] = {0}; if((fp = fopen("test.txt","r+")) == NULL){ perror("fopen"); return -1; } while(1){ if(fgets(buf,M,fp) == NULL){ perror("fgets"); break; } printf("test look:%s",buf); } printf("fgets from file ok\n"); fclose(fp); return 0; }
fputs/puts行输出接口函数

#include <stdio.h> #define N 32 int main(int argc, const char *argv[]) { FILE * fp = NULL; char buf[N] = {0}; if((fp = fopen("test.txt","a+")) == NULL ){ perror("fopen"); return -1; } if(fgets(buf,N,stdin) == NULL){ perror("fgets"); fclose(fp); return -1; } if(fputs(buf, fp) == EOF){ perror("fputs"); fclose(fp); return -1; } fclose(fp); return 0; }
实践:统计文本行
#include <stdio.h> #include <string.h> #define N 32 int main(int argc, const char *argv[]) { FILE * fp = NULL; int cout = 0; char buf[N] = {0}; if((fp = fopen("test.txt","a+")) == NULL){ perror("fopen"); return -1; } while(1){ if(fgets(buf,N,fp) == NULL){ perror("fgets"); break; } if(buf[strlen(buf)-1] == '\n'){ cout++; } } printf("cout = %d\n",cout); fclose(fp); return 0; }

10.标准IO:文件的二进制读写与对象读写

fread、fwrite二进制读写接口函数

fread接口函数:

fwrite接口函数:

fflush函数:刷新,立即将缓冲区内容交给内核

#include <stdio.h> #include <unistd.h> typedef struct note { int id; char name[8]; float score; }STU; int main(int argc, const char *argv[]) { FILE * fp = NULL; if((fp = fopen("test.txt","a+")) < 0){ perror("perror"); return -1; } STU s[2] = {{1,"wang",98},{2,"li", 95}}; int len = sizeof(STU); if(fwrite(&s[0],len,1,fp) < 0){ perror("fwrite"); return -1; } fflush(fp); sleep(5); if(fwrite(&s[1],len,1,fp) < 0){ perror("fwrite"); return -1; } fclose(fp); if((fp = fopen("test.txt","r+")) < 0){ perror("perror"); return -1; } STU ret; fread(&ret, len,1,fp); printf("%d,%s,%f\n",ret.id,ret.name,ret.score); fclose(fp); return 0; }
bzero清空函数

bzero(buf,sizeof(buf));将数组buf的sizeof(buf)个成员变成'\0'

feof判断结尾函数

feof(流) 返回值为非零时,文件到结尾了。返回值为0时,文件没到结尾。

实践:二进制读写复制文件
#include <stdio.h> #include <string.h> #define N 512 int main(int argc, const char *argv[]) { FILE *fp_r = NULL,*fp_w = NULL; if(argc < 3){ printf("Usage :%s <source file><destination file>\n",argv[0]); return -1; } if((fp_r = fopen(argv[1],"r")) == NULL){ printf("fopen source file failed\n"); return -1; } if((fp_w = fopen(argv[2],"a+")) == NULL){ printf("fopen destination file failed\n"); return -1; } char buf[N]; size_t bytes_read,bytes_write; while(1){ if(feof(fp_r)){ printf("read file in last line\n"); break; } if((bytes_read = fread(buf,1,sizeof(buf), fp_r)) < 0){ printf("fread failed\n"); goto END; } if((bytes_write = fwrite(buf,1,bytes_read, fp_w)) < 0){ printf("fread failed\n"); goto END; } if(bytes_read != bytes_write){ printf("failed to write to destination file\n"); goto END; } bzero(buf,sizeof(buf)); } printf("file copied successfully from '%s' to '%s'\n",argv[1],argv[2]); END: fclose(fp_r); fclose(fp_w); return 0; }
fscanf、sscanf、fprintf、sprintf 格式化输入、输出函数

11.标准IO操作、流的刷新与定位

fflush流的刷新

ftell、rewind、fseek流的定位函数

实践:获取文本大小

12.目录操作

opendir、fdopendir打开目录函数

closedir关闭目录函数

dirent访问目录函数

实践:获取文件夹中的内容

stat 、lstat、fstat 获取文件属性函数

属于 man 2 stat

实践:获取文件信息
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <time.h> int main(int argc, const char *argv[]) { if(argc < 2){ printf("Usage :%s <filename>\n",argv[1]); return -1; } struct stat st; #if 1 if(stat(argv[1],&st) == -1){ perror("stat"); return -1; } #elif 0 if(lstat(argv[1],&st) == -1){ perror("lstat"); return -1; } printf("file size:%ld\n",st.st_size); #else int fd = open(argv[1],O_RDONLY); if(fd < 0){ perror("open"); return -1; } fstat(fd,&st); printf("ffile size:%ld\n",st.st_size); #endif switch(S_IFMT&st.st_mode){ case S_IFREG: putchar('_'); break; case S_IFDIR: putchar('d'); break; case S_IFSOCK: putchar('s'); break; case S_IFLNK: putchar('l'); break; case S_IFBLK: putchar('b'); break; case S_IFCHR: putchar('C'); break; case S_IFIFO: putchar('f'); break; default: printf("have afailed\n"); return -1; } int n = 8; do{ if(st.st_mode & (0x1<<n)){ switch(n%3){ case 0: putchar('x'); break; case 1: putchar('w'); break; case 2: putchar('r'); break; } }else{ putchar('-'); } }while(n--); printf(" file size:%ld\t",st.st_size); printf("\t%s",ctime(&st.st_ctime)); return 0; }

13.程序库(静态库、动态库)

静态库

动态库

静态库和动态库区别

http://www.jsqmd.com/news/935797/

相关文章:

  • 基于Arduino Leonardo/Micro打造12轴USB摇杆控制器:从HID协议到实战
  • 【RT-DETR实战】 119、瑞芯微RKNN平台部署实战:从模型转换到板端推理的坑与经验
  • 惠城黄金回收哪家强?惠奢汇(惠城旗舰店)等你来选! - 生活测评小能手
  • 基于数字逻辑芯片的密码锁系统:从原理到硬件实现
  • 抖音下载器终极指南:3分钟学会批量下载无水印视频
  • SCOPE:语义认知驱动的前沿潜力探索与具身视觉导航实践
  • 集团首都公报:武汉市放飞炬人产业引导基金有限责任公司财政处批准 创设 集体组织债 资本市场种品 将来为农村集体经济组织和乡镇经济管理提供资本来源和货币供应。
  • ComfyUI-VideoHelperSuite视频处理模块防御性编程实践与零除错误修复
  • Python 从不起眼到AI时代的王者之路
  • 【Web安全】-10-网站关键信息收集:目录扫描的概念,工具目录扫描(内含御剑,FindSomething安装链接),网站服务器收集,操作系统判断
  • 中老年人能用的免费证件照制作入口推荐?2026爸妈也能自己操作的证件照工具 - 科技大爆炸
  • Claude Code + PowerShell 命令大全:从入门到精通
  • 基于Tinkercad仿真的Arduino避障机器人:从虚拟到实物的嵌入式开发实践
  • 基于Arduino Nano RP2040的DIY可编程USB游戏手柄全流程开发指南
  • 计算机软件转 IC 验证(Design Verification, DV),学习路径
  • 从零打造垂直XY绘图机器人:Arduino步进电机控制与Makelangelo软件实战
  • 惠州黄金奢侈品回收综合实力排行榜2026中检认证正规门店梯队推荐(惠奢汇惠城旗舰店领衔) - 生活测评小能手
  • 大量频繁数据更新表格不卡顿的核心原因(通用原理 + 对应上套代码的设计)
  • 别再手动查漏洞了!用OWASP DependencyCheck给你的Maven项目做个自动化体检(附Jenkins流水线配置)
  • 基于Arduino与超声波传感器的智能扫地机器人V2.0设计与实现
  • DPDK 程序为什么越优化越慢?——深入理解数据面的“伪优化陷阱”
  • 参数化CAD设计实战:从创意草图到三维装配的完整流程解析
  • 抖音高清下载终极指南:免费获取无水印视频、音乐和封面
  • 【CGLIB】在你熟悉的 Flink、ShardingSphere-JDBC 等组件中,是否存在 CGLIB 的使用痕迹?如何排查?
  • Arduino超声波测距系统:从传感器原理到社交距离监测器实战
  • 办公用的免费证件照制作入口有什么?2026职场人必备免费入口 - 科技大爆炸
  • 2026重庆GEO优化公司TOP10:技术实力与服务能力全景测评 - 品牌官
  • 天赐范式第61天:为“雨”平反——从一次大模型“服务器繁忙”看 PDE 求解器的代数独立性——何以解忧,唯有杜康~
  • 告别动画重复K帧!用UE5的IK重定向器,5分钟让女武神动作适配你的自定义角色
  • 5个关键步骤掌握WorkshopDL:跨平台Steam创意工坊模组下载实战指南