news 2026/6/2 12:27:59

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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.程序库(静态库、动态库)

静态库

动态库

静态库和动态库区别

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/2 12:25:56

猫抓浏览器资源嗅探扩展:从网页流媒体中提取内容的终极指南

猫抓浏览器资源嗅探扩展&#xff1a;从网页流媒体中提取内容的终极指南 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 猫抓Cat-Catch是一款功能强…

作者头像 李华
网站建设 2026/6/2 12:21:56

【Web安全】-10-网站关键信息收集:目录扫描的概念,工具目录扫描(内含御剑,FindSomething安装链接),网站服务器收集,操作系统判断

&#x1f986; 个人主页&#xff1a;深邃- ❄️专栏传送门&#xff1a;《C语言》《数据结构与算法》《Web安全》 &#x1f31f;Gitee仓库&#xff1a;《C语言》《数据结构与算法》 本博客是本作者学习与总结的分享&#xff0c;仅作为学习分享&#xff0c;禁止用于非法用途 目录…

作者头像 李华
网站建设 2026/6/2 12:21:02

DPDK 程序为什么越优化越慢?——深入理解数据面的“伪优化陷阱”

一、一次失败的性能优化几年前&#xff0c;我参与过一个基于 DPDK 的用户态网关项目。系统结构并不复杂&#xff1a;RX↓ Session Lookup↓ Policy Process↓ TX初版实现非常简单&#xff1a;单线程处理Hash 查表少量业务逻辑测试结果&#xff1a;64B Packet单核 8Mpps虽然谈不…

作者头像 李华
网站建设 2026/6/2 12:20:58

服务网格(Service mesh istio)

倚天剑与屠龙刀之侍从篇:服务网格(Istio)深度解析 “微服务与Kubernetes是倚天剑和屠龙刀,而服务网格,就是那持剑握刀的‘侍从’——它不直接砍杀,却让每一次出鞘都精准、安全、可观测。” 引言:架构演进中的“静默革命” 微服务架构带来了业务解耦,Kubernetes解决了基…

作者头像 李华
网站建设 2026/6/2 12:17:55

变分方法(variational method)做上采样,替代线性插值

“变分方法&#xff08;variational method&#xff09;”本质上不是在做“插值”&#xff0c;而是在做一个带约束的优化问题求解&#xff1a;把“上采样”变成“找一个最合理的高分辨率解”。 1. 它不是“放大”&#xff0c;而是“重新求解” 双线性上采样做的是&#xff1a…

作者头像 李华
网站建设 2026/6/2 12:16:24

基于帕尔贴效应的DIY桌面加热器:从热电原理到工程实践

1. 项目概述&#xff1a;从热电效应到桌面暖手宝如果你对电子DIY或者热管理技术有点兴趣&#xff0c;大概听说过“半导体制冷片”这个东西。它的大名其实叫“帕尔贴模块”&#xff0c;核心原理就是“帕尔贴效应”。简单来说&#xff0c;当你给一块由两种不同半导体材料组成的模…

作者头像 李华