Linux——库函数
- 创业
- 2025-09-06 10:21:02

一、基本概念
文件: 一组相关数据的集合 文件名: 01.sh //文件名
流:
流是指数据在程序或系统中的流动方式。在Linux中,数据流通常通过文件描述符(File Descriptors)进行管理。文件描述符是一个非负整数,用于标识打开的文件或输入/输出资源。
二、linux下的文件类型b block 块设备文件 eg: 硬盘 c character 字符设备文件 eg: 鼠标,键盘 d directory 目录文件 eg: 文件夹 - regular 常规文件 eg: 1.txt 01.sh xx.bmp l symblink 软链接 eg: 快捷方式 s socket 套接字 eg: 网络通信用 p pipe 管道 eg: 进程间通信
三、思想linux中一个核心设计思想 everything is file! //一切皆文件
四、 linux操作文件的函数两套函数 (两套操作路径
(一)库函数--- 第三方提供的函数
集成了很多功能函数 //标准输入输出 //数学函数
(二)系统调用--- 内核提供的函数
(三)标准io的概念1975 Dennis r IO库, 从C语言的标准,ANSI c IO input output I: 键盘是标准输入设备 ====》默认输入就是指键盘 /dev/input O: 显示器是标准输出设备 ==》默认输出就是指显示器 Linux操作系统当中IO都是对文件的操作 C一部分,任何支持标准C的系统都可使用标准IO实现文件存储 标准IO在UNIX上是对文件IO的封装 一般都是对普通文件操作是一种有缓存的IO 在文件IO和用户程序之间, 加入缓冲区,可以有效减少系统调用的次数,节省系统IO调度资源 说明: 标准IO库,不单单是linux上有,在windows,Mac os上都有。 很多操作系统都实现了标准IO库。 都是依据IOS C标准实现的。 所以基本保证了可移植性。 但是因为标准和具体实现之间的差异, 未必敢保证所有的函数在都可以相互通用。 标准IO都干了些啥? 标准IO处理了很多细节: (1).处理缓冲区分配 (缓存--提高效率 --- 慢速 快速) (2).读写IO的块长度的优化 (3).对系统调用进行了封装,内部对应的"文件描述符" 好处: 用户使用方便,不必再担心如何选择正确的块长度。 //地位: 标准I/O库是由 Dennis Ritchie在1975年左右编写的。 它是Mike Lesk编写的可移植I/O库的主要修改版本。 令人惊讶的是,50年来,几乎没有对标准I/O库进行修改。
五、函数接口 (一)fopenFILE * fopen(const char *pathname,const char *mode); 功能: 流打开函数 参数: @pathname --- 要打开的文件名 //字符串形式的名字 @mode --- 打开的模式 r --- 只读 r+ --- 读写 说明: 带r的 要求,文件必须存在 ,如果不存在,就会报错 w --- 只写 w+ --- 读写 说明: 文件存在 ,截断成 0长度 不存在,则创建 a --- 追加(写) a+ --- 读写 说明: 读 从头读 写 从末尾开始写 文件存在 则打开做写操作即可 文件不存在 创建文件 返回值: 成功 FILE*指针 //文件指针 流指针 --- 从程序上讲,FILE *指针就代表打开的这个文件 失败 NULL 同时 errno会被设置
#include<stdio.h> #include<errno.h> int main(int argc, const char *argv[]) { if (argc != 2) { printf("Usage: %s <filename>\n",argv[0]); return -1; } FILE *fp = fopen(argv[1],"w+"); // FILE *fp = fopen(argv[1],"r+"); if(fp == NULL) { printf("fopen fail\n"); return -1; } // printf ("fopen success!\n"); return 0; } (二)perrorvoid perror(const char *s);
#include<stdio.h> #include<errno.h> int main(int argc, const char *argv[]) { if (argc != 2) { printf("Usage: %s <filename>\n",argv[0]); return -1; } FILE *fp = fopen(argv[1],"r"); if(fp == NULL) { perror("fopen fail"); return -1; } printf ("fopen success!\n"); return 0; } (三)fgetc 、fputc1、 int fgetc(FILE * stream);
功能: 从文件中读取字符 参数: @stream 表示要读取的文件对应的流指针 返回值: 成功 对应字符的ASCII码值 失败 EOF 到达文件结尾 出错
2、int fputc(int c,FILE *stream);功能: 将一个字符输出到指定的流(文件) 参数: @c //要输出的字符 ---ascii码值 @stream //指定的文件 返回值: 成功 被写入的字符的ASCII码值 失败 EOF
问题: EOF 文件中有没有 EOF? //只是到达结尾时的一个标志
#include<stdio.h> #include<errno.h> //类似cat功能 int main(int argc, const char *argv[]) { //处理命令行参数 if (argc != 2) { printf("Usage: %s <filename>\n",argv[0]); return -1; } //1.打开文件 FILE *fp = fopen(argv[1],"r+"); if(fp == NULL) { perror("fopen fail"); return -1; } //2.读写数据 int ret; while((ret = fgetc(fp)) != EOF) { fputc(ret,stdout); //printf("%c",ret); } //3.关闭 fclose(fp); return 0; }系统默认打开的流指针: stdin //标准输入 stdout //标准输出 stderr //标准出错 --- 屏幕 --- 可以专门把错误信息输出到 stderr
#include<stdio.h> int main(int argc, const char *argv[]) { int ret; while ( (ret = fgetc(stdin)) != EOF) fputc(ret,stdout); return 0; } (四)fcloseint fclose(FILE *stream); 功能: 关闭文件 刷新流 关闭了底层文件描述符 返回值: 成功 0 失败 EOF 注意,不要多次重复关闭
(五)fgets、fputs 1、char * fgets(char*s,int size,FILE*stream)功能: 从stream中读取size-1个字符,到s指向的空间 参数: @s //存放读取到的数据 对应的内存空间 @size //指定一次最多读取多少个字符 @stream //表示要读取的文件 返回值: 成功 返回s 失败 NULL 读到文件结尾 也 返回NULL
注意: fgets读取结束: 1. EOF 2. '\n' 3. size-1
练习: 统计文件行数
#include<stdio.h> #include<errno.h> #include<string.h> int main(int argc, const char *argv[]) { if(argc != 2) { printf("Usage: %s <filename>\n",argv[0]); return -1; } FILE *fp = fopen(argv[1],"r+"); if(fp == NULL) { perror("fopen fail"); return -1; } char buf[1024]; int n = 0; while (fgets(buf,sizeof(buf),fp)) { if(buf[strlen(buf) - 1] == '\n') { n++; } } printf("%d\n",n); fclose(fp); return 0; }2、int fputs(const char *s, FILE *stream);
功能: 输出s到stream中 参数: @s 代表要输出的字符串 @stream 代表 输出到的文件 返回值: 成功 非负数 失败 EOF
注意: 不会将 '\0' 输出
练习: cat //fgets实现cat
#include<stdio.h> #include<errno.h> //类似cat功能 int main(int argc, const char *argv[]) { //处理命令行参数 if (argc != 2) { printf("Usage: %s <filename>\n",argv[0]); return -1; } //1.打开文件 FILE *fp = fopen(argv[1],"r+"); if(fp == NULL) { perror("fopen fail"); return -1; } //2.读写数据 int ret; while((ret = fgetc(fp)) != EOF) { fputc(ret,stdout); //printf("%c",ret); } //3.关闭 fclose(fp); return 0; }cp_fputsfgets.c
#include<stdio.h> #include<errno.h> int main(int argc, const char *argv[]) { if (argc != 3) { printf("Usage: %s <filename>\n",argv[0]); return -1; } FILE *fp = fopen(argv[1],"r"); FILE *srt = fopen(argv[2],"w"); if(fp == NULL || srt == NULL) { printf("fopen fail\n"); return -1; } char buf[1024]; while(fgets(buf,1024,fp) != NULL) { fputs(buf,srt); } fclose(fp); fclose(srt); return 0; }"123" --- 文本文件 --- '1''2''3' //每个数据是按照固定的编码格式存放的 -ASCII 123 --- 二进制 --- 01111011 // linux下操作时 ,没有区别 windows下区别 说明: 1.fgets 和 fputs 在拷贝 二进制文件时 可能出问题
(六)fread / fwritefread/fwrite //二进制读写函数 按对象读写
1、size_t fread( void *ptr, size_t size, size_t nmemb, FILE *stream); 2、size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);功能: 二进制流的读/写 参数: @ptr 表示存放数据的空间的地址 @size 要操作的单个元素(对象)的大小 @nmemb 要操作的元素(对象)的个数 @stream 要操作的文件 返回值: 成功 返回的是 成功操作到的对象的个数 失败 0 到达文件结尾 返回 0 应用: 主要 应用在 文件中 有固定格式的 场景
#include<stdio.h> int main(int argc, const char *argv[]) { char buf[10]; int ret = fread(buf,sizeof(char),10,stdin); printf("ret = %d\n",ret); fwrite(buf,sizeof(char),ret,stdout); putchar('\n'); return 0; }练习: 将3个学生的信息,写到文件中 之后, 从文件中读出学生信息,打印
#include<stdio.h> typedef struct stu { char name[20]; int sno; float score; }stu_t; int main(int argc, const char *argv[]) { stu_t s[3] = {{"tom",110,99}, {"liam",111,98}, {"beta",112,99}}; FILE *fp = fopen("stu.txt","w+"); if(fp == NULL) { perror("fopen fail"); return -1; } fwrite(s,sizeof(stu_t),3,fp); rewind(fp); stu_t s1[3]; fread(s1,sizeof(stu_t),3,fp); int i = 0; for(i = 0;i < 3;i++) { printf("name = %s\n",s1[i].name); printf("sno = %d\n",s1[i].sno); printf("score = %.2f\n",s1[i].score); } fclose(fp); return 0; }cat_fread_fwrite.c
#include<stdio.h> int main(int argc, const char *argv[]) { if(argc != 2) { printf("Usag: %s <filename>\n",argv[0]); } FILE *fp = fopen(argv[1],"r"); if(fp == NULL) { perror("fopen fail"); return -1; } char buf[1024]; int ret = 0; while(ret =fread(buf,sizeof(char),1024,fp)) fwrite(buf,sizeof(char),ret,stdout); fclose(fp); putchar('\n'); return 0; } (七)文件偏移量 rewindint fseek(FILE* stream,long offset,int whence); 功能: 定位文件 参数: @stream 表示要操作文件 @offset 表示文件偏移量 @whence 定位的参考点 SEEK_SET //相对于文件开头的 offset >=0 SEEK_CUR //相对于当前位置 offset>=0 offset<0 //不能超过这个文件开头 SEEK_END //相对于文件末尾 offset < 0 //不能超过这个文件开头 offset >= 0 //可以 --- 创建 空洞 文件 返回值: 成功 0 失败 -1
fseek(fp,100,SEEK_SET);// fseek(fp,0,SEEK_SET);//定位到开头 fseek(fp,0,SEEK_END);//定位到末尾应用:
创建空洞文件: 1.做偏移 2.写操作
#include<stdio.h> int main(int argc, const char *argv[]) { if(argc != 2) { printf("Usage: %s <filename>\n",argv[0]); return -1; } FILE *fp = fopen(argv[1],"r"); if(fp == NULL) { perror("file fail"); return -1; } if(fseek(fp,100,SEEK_END) != 0) { perror("fseek fail"); return -1; } fputc('A',fp); fclose(fp); return 0; } (八) long ftell(FILE*stream);功能: 获得当前文件的偏移量 void rewind(FILE*stream); 功能: 将文件偏移量设置到文件开头
获得某个文件的大小: 1. fseek(fp,0,SEEK_END);//定位到末尾 2. long len =ftell(fp);
实现 cp功能
#include<stdio.h> int main(int argc, const char *argv[]) { if(argc != 3) { printf("Usage: %s <src> <dest>\n",argv[0]); return -1; } FILE *fp1 = fopen(argv[1],"r"); if(fp1 == NULL) { perror("file fail"); return -1; } fseek(fp1,0,SEEK_END); long len = ftell(fp1); FILE *fp2 = fopen(argv[2],"w"); if(fp2 ==NULL) { perror("file fail"); return -1; } fseek(fp2,len-1,SEEK_SET); fputc('\0',fp2); rewind(fp1); rewind(fp2); char buf[len]; fread(buf,sizeof(buf),1,fp1); fwrite(buf,sizeof(buf),1,fp2); fclose(fp1); fclose(fp2); return 0; } 六、缓存缓存 设计的目的提高效率 本质上来说 ---缓存其实就是一块内存空间
行缓冲,1k, terminal,主要用于人机交互stdout 缓存区满或者遇到\n刷新 1024 行缓存多是关于终端的一些操作 1.遇到\n刷新 2.缓存区满刷新 3.程序结束刷新 4.fflush刷新 fflush(stdout); 全缓冲,4k,主要用于文件的读写 缓存区满刷新缓存区 4096 对普通文件进行标准IO操作,建立 的缓存一般为全缓存 刷新条件: 1.缓存区满刷新 2.程序结束刷新 3.fflush来刷新 fflush(fp); 无缓冲,0k 主要用于出错处理信息的输出 stderr 不对数据缓存直接刷新 printf();==>>stdout fprintf(strerr,"fopen error %s",filename); 界面交互 出错处理
./a.out < main.c //< 表示输入重定向 ./a.out > main.c //> 表示输出重定向
七、作业1、统计一个文件中出现英文字母出现的次数
#include<stdio.h> #include<fcntl.h> #include<unistd.h> int main(int argc, const char *argv[]) { if(argc != 2) { printf("Usage: %s <filename>\n",argv[0]); return -1; } int fd = open(argv[1],O_RDONLY); if(fd < 0) { perror("file fail"); return -1; } unsigned char ch; int n[26] = {0}; while(read(fd,&ch,1) != 0) { if(ch >= 'a' && ch <= 'z') { n[ch - 'a']++; } else if(ch >= 'A' && ch <= 'Z') { n[ch - 'A']++; } } int i = 0; for(i = 0;i < 26;i++) { printf("%c:%d\n",i+'a',n[i]); } close(fd); return 0; }二、完成两个图片的拼接
把第一个有色点写入第二个文件,使第二个文件和第三个文件的图片一样
#include<stdio.h> #include<stdlib.h> #pragma pack(1) //保证结构体的紧凑,编译器指令,控制成员的对齐方式为按1字节对齐 typedef struct { unsigned char b; unsigned char g; unsigned char r; } pixel; int pixel_white(pixel p) { return (p.r == 255 && p.g == 255 && p.b == 255); } int main(int argc, const char *argv[]) { //参数检查 if(argc != 3) { printf("Usage: %s <file1.bmp> <file2.bmp>\n",argv[0]); return -1; } //打开文件(进入二进制读写模式) FILE *fp1 = fopen(argv[1],"rb+"); FILE *fp2 = fopen(argv[2],"rb+"); if(fp1 == NULL || fp2 == NULL) { perror("file fail"); return -1; } //跳过54字节头文件 if(fseek(fp1,54,SEEK_SET ) || fseek(fp2,54,SEEK_SET)) { perror("fseek fail"); return -1; } //读取并比较像素 pixel p1,p2; long pos = 54; //记录当前文件位置 while(1) { size_t read1 = fread(&p1,sizeof(pixel),1,fp1); size_t read2 = fread(&p2,sizeof(pixel),1,fp2); if(read1 != 1 || read2 != 1) break; if(pixel_white(p2)) { fseek(fp2,pos,SEEK_SET); //回退文件指针 fwrite(&p1,sizeof(pixel),1,fp2); fflush(fp2); } pos += sizeof(pixel); //更新位置 } fclose(fp1); fclose(fp2); return 0; }把两个图片拼接成第三个
#include <stdio.h> // ./a.out 1.bmp 2.bmp 3.bmp int main(int argc, const char *argv[]) { if (argc != 4) { printf("usage: %s <src1.bmp> <src2.bmp> <dest.bmp>\n", argv[0]); return -1; } FILE *fp1 = fopen(argv[1], "r"); FILE *fp2 = fopen(argv[2], "r"); FILE *fp3 = fopen(argv[3], "w"); if (fp1 == NULL || fp2 == NULL || fp3 == NULL) { perror("open fail"); return -1; } unsigned char head1[54]; unsigned char head2[54]; unsigned char body1[600*800*3]; unsigned char body2[600*800*3]; fread(head1, sizeof(unsigned char), 54, fp1); fread(body1, sizeof(unsigned char), 600*800*3, fp1); fread(head2, sizeof(unsigned char), 54, fp2); fread(body2, sizeof(unsigned char), 600*800*3, fp2); int i = 0; for (i = 0; i < 600 * 800 * 3; ++i) { if (!((body1[i] == 255 && body1[i+1] == 255 && body1[i+2] == 255)) { body2[i] = body1[i]; body2[i+1] = body1[i+1]; body2[i+2] = body1[i+2]; } } fwrite(head2, sizeof(char), 54, fp3); fwrite(body2, sizeof(char), 600*800*3, fp3); fclose(fp1); fclose(fp2); fclose(fp3); return 0; }Linux——库函数由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Linux——库函数”