Day32 文件属性 目录操作 库

文章目录

  • 获取文件属性
    • 1.stat函数
    • 2.获取文件属性
    • 3.获取文件权限
    • 4.stat/fstat/lstat的区别?
  • 目录操作
  • 库 Lib
    • 1.库的定义
    • 2.库的分类
      • 2.1 静态库
      • 2.2 动态库
    • 3.静态库的制作
    • 4.动态库制作
    • 5.总结静态库和动态库

获取文件属性

1.stat函数

int stat(const char *path, struct stat *buf);
功能:获取文件属性
参数:  path:文件路径名buf:保存文件属性信息的结构体
返回值:成功:0失败:-1
struct stat {ino_t     st_ino;     /* inode号 ls -il */     mode_t    st_mode;    /* 文件类型和权限 */nlink_t   st_nlink;   /* 硬链接数 */uid_t     st_uid;     /* 用户ID */gid_t     st_gid;     /* 组ID */off_t     st_size;    /* 大小 */time_t    st_atime;   /* 最后访问时间 */time_t    st_mtime;   /* 最后修改时间 */time_t    st_ctime;   /* 最后状态改变时间 */};

打印inode号,链接数,大小:

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>int main(int argc, char const *argv[])
{struct stat st;if(stat("a.c",&st)<0){perror("stat err");return -1;}printf("inode:%lu nlink:%d size:%ld\n",st.st_ino,st.st_nlink,st.st_size);return 0;
}

2.获取文件属性

在这里插入图片描述S_IFMT是一个掩码,它的值是0170000(注意这里用的是八进制前缀为0,二进制为0b1111000000000000), 可以用来过滤出四位表示的文件类型

在这里插入图片描述
例如:
在这里插入图片描述

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>int main(int argc, char const *argv[])
{struct stat st;if (stat(".", &st) < 0){perror("stat err");return -1;}printf("inode:%lu nlink:%d size:%ld\n", st.st_ino, st.st_nlink,st.st_size);printf("%#o\n", st.st_mode);//判断文件类型if ((st.st_mode & __S_IFMT) == __S_IFREG)printf("regular file\n");else if ((st.st_mode & __S_IFMT) == __S_IFDIR)printf("directory\n");//或者用宏函数if (S_ISREG(st.st_mode))printf("-");else if (S_ISDIR(st.st_mode))printf("d");return 0;
}

3.获取文件权限

在这里插入图片描述

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>int main(int argc, char const *argv[])
{struct stat st;if (stat(".", &st) < 0){perror("stat err");return -1;}printf("inode:%lu nlink:%d size:%ld\n", st.st_ino, st.st_nlink,st.st_size);printf("%#o\n", st.st_mode);//判断文件权限//个人权限if (st.st_mode & S_IRUSR)putchar('r');elseputchar('-');if (st.st_mode & S_IWUSR)putchar('w');elseputchar('-');if (st.st_mode & S_IXUSR)putchar('x');elseputchar('-');return 0;
}

4.stat/fstat/lstat的区别?

stat函数返回一个与此命名文件有关的信息结构
fstat函数获得已在描述符filedes上打开的文件的有关信息,也就是参数是文件描述符,其他与stat相同。
lstat函数类似于stat,但是当命名的文件是一个符号连接时,lstat返回该符号连接的有关信息,而不是由该符号连接引用的文件的信息.

目录操作

围绕目录流进行操作: DIR *
opendir
closedir
readdir
chdir

DIR *opendir(const char *name);
功能:获得目录流
参数:要打开的目录
返回值:成功:目录流失败:NULLstruct dirent *readdir(DIR *dirp);
功能:读目录
参数:要读的目录流
返回值:成功:读到的信息    失败:NULL
返回值为结构体,该结构体成员为描述该目录下的文件信息struct dirent {ino_t   d_ino;               /* 索引节点号*/off_t   d_off;               /*在目录文件中的偏移*/unsigned short d_reclen;     /* 文件名长度*/unsigned char  d_type;       /* 文件类型 */char    d_name[256];         /* 文件名 */
};int closedir(DIR *dirp);
功能:关闭目录
参数:dirp:目录
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>int main(int argc, char const *argv[])
{DIR *dir;struct dirent *d;dir = opendir(".");if (NULL == dir){perror("opendir err");return -1;}printf("opendir success\n");d = readdir(dir);printf("%s\n", d->d_name);d = readdir(dir);printf("%s\n", d->d_name);closedir(dir);return 0;
}

实现 ls

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>int main(int argc, char const *argv[])
{DIR *dir;struct dirent *d;dir = opendir(".");if (NULL == dir){perror("opendir err");return -1;}printf("opendir success\n");while ((d=readdir(dir))!=NULL) //循环读,读到内容就打印printf("%s\n",d->d_name);closedir(dir);return 0;
}

注意:这里顺序不是按照ls排序的顺序,因为ls自身有个排序算法。这里是按照文件在磁盘的顺序读取的。

库 Lib

头文件:#include<stdio.h>
<>代表去系统路径下查找头文件 /usr/inlude
#include “head.h”
""代表先去当前路径下查找,找不到再去系统路径下查找

源文件: 包含main函数的 xx.c
包含子函数的 xx.c , 封装的函数的声明需要放在头文件里

库文件(不能包含main函数)

分文件编程:
main.c

#include "head.h"main()
{fun();
}

fun.c

void fun()
{}

head.h

void fun();

编译: gcc main.c fun.c
优点:编译简单,只需要编译所有.c文件就可以了
缺点:随着工程变大,占用空间变大。所以可以使用库文件的方法进行编译。

库文件:二进制文件
可以把fun.c做成库文件,这样编译的时候就不需要编译fun.c了,只需要连接生成的库就可以了。
gcc main.c -lxxx

1.库的定义

当使用别人写好的函数时除了包含头文件还可以需要库
头文件: 函数声明、宏定义、结构体定、联合体、枚举定义、重命名、外部引用、其他头文件
库:把一些常用的函数的目标文件打包在一起,提供相应的函数接口,便于程序员使用。本质上来说库是一种可执行代码的二进制形式文件。
由于windows和linux的本质不同,因此而这库的二进制是不兼容的。(Linux中的C运行库是glibc, 由GUN发布。)

2.库的分类

静态库和动态库,本质区别是代码载入的时刻不同

2.1 静态库

静态库在程序编译时会被复制到目标代码中, 以.a结尾。
优点:程序运行时将不再需要该静态库;运行时无需加载库,运行速度更快
缺点:静态库中的代码复制到了程序中,因此体积较大;静态库升级后,程序需要重新编译链接所以升级难。

2.2 动态库

动态库是在程序运行时才被载入代码中。也叫共享库,以.so结尾。
优点:程序在执行时加载动态库,代码体积小;程序升级更简单;
不同应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
缺点:运行时还需要动态库的存在,移植性较差。

3.静态库的制作

(1)将源文件编译生成目标文件
gcc -c fun.c -o fun.o
(2)创建静态库ar命令, 将很多.o 转换成.a
ar crs libmyfun.a fun.o
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a
(3)测试使用静态库:
gcc main.c -L. -lmyfun //-L指定库的路径,-l指定库名
执行: ./a.out
在这里插入图片描述

4.动态库制作

(1)用gcc来制作共享库也就是动态库
gcc -fPIC -c fun.c -o fun.o //-fPIC 创建与地址无关的编译程序
gcc -shared -o libmyfun.so fun.o
(2)测试动态库并使用
gcc main.c -L. -lmyfun
./a.out: 可以正常编译通过,但是运行时报错error while loading shared libraries: libmyadd.so: cannot open shared object file: No such file or directory

原因:当加载动态库时,系统会默认从/lib或/usr/lib路径下查找库文件,所以不用-L加路径了,直接gcc main.c -lmyfun就可以了

解决方法(有三种):
1)把库拷贝到/usr/lib和/lib目录下。(此方法编译时不需要指定库的路径)
2)在LD_LIBRARY_PATH环境变量中加上库所在路径。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
(终端关闭,环境变量就没在了)
3)添加/etc/ld.so.conf.d/*.conf文件。把库所在的路径加到文件末尾,并执行ldconfig刷新
sudo vi xx.conf
添加动态库存在的路径,如:
/home/hq/work/lib
在这里插入图片描述
-L路径:指定库的路径
-I(大写i)路径:指定头文件的路径 默认查找的路径/usr/include
#include <stdio.h> //从系统路径下查找头文件
#include “head.h” //从当前路径下查找此头文件
ldd 可执行文件名:查看链接的动态库

注意:
同名的静态库和动态库:默认优先使用动态库,如果想使用静态库 需要在后面加 -static,这是内核规定的。
如果链接没有lib前缀的库文件,可以直接用-指定库的全名无需加l选项。

5.总结静态库和动态库

静态库:编译阶段,体积大,移植性好,升级麻烦。
动态库:运行阶段加载,体积小,移植性差,升级简单。

可以看出用静态库编译生成的程序体积大一些:
在这里插入图片描述
升级演示:改变源文件fun.c
动态库只需要重新生成动态库,不需要重新编译。
在这里插入图片描述
静态库需要重新编译
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/483738.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#,二叉搜索树(Binary Search Tree)的迭代方法与源代码

1 二叉搜索树 二叉搜索树&#xff08;BST&#xff0c;Binary Search Tree&#xff09;又称二叉查找树或二叉排序树。 一棵二叉搜索树是以二叉树来组织的&#xff0c;可以使用一个链表数据结构来表示&#xff0c;其中每一个结点就是一个对象。 一般地&#xff0c;除了key和位置…

uni-app 开发调试自动打开手机屏幕大小界面(Aidex移动端开发项目)

上效果&#xff1a; 下载Aidex的移动端项目并打开&#xff1a; 若依-ruoyi-AiDex-Uniapp: 若依-Ruoyi APP 移动解决方案&#xff0c;基于uniappuView封装的一套基础模版&#xff0c;开箱即用&#xff0c;免费开源&#xff0c;一份代码多终端适配&#xff0c;支持H5、支付宝小程…

Kotlin基础 7

1.apply函数详解 1.1. DSL /*** 为什么要传入扩展函数(泛型),而不是一个普通的匿名函数* T.()->Unit* 扩展函数里自带了接收者对象的this隐式调用* 为什么是泛型的扩展函数?* 因为是由this 隐式调用 this 类型就是泛型类型&#xff0c; 相当于this的扩展函数&#xff0c;…

Aidex移动端项目入门

运行效果 项目源码下载 若依-ruoyi-AiDex-Uniapp: 若依-Ruoyi APP 移动解决方案&#xff0c;基于uniappuView封装的一套基础模版&#xff0c;开箱即用&#xff0c;免费开源&#xff0c;一份代码多终端适配&#xff0c;支持H5、支付宝小程序、微信小程序、APP&#xff0c;实现了…

解决MobaXterm网络错误连接超时问题

报错页面&#xff1a; 报错原因&#xff1a; ①网络断开了 ②网络端口&#xff0c;端口号改变 解决办法&#xff1a; ①重新连接网络按R ②固定端口号 第一步&#xff1a;编辑------>虚拟机网络编辑器&#xff08;我的Linux在虚拟机里&#xff09; 第二步&#xff1a;用…

Chrome插件精选 — 缓存清理

Chrome实现同一功能的插件往往有多款产品&#xff0c;逐一去安装试用耗时又费力&#xff0c;在此为某一类型插件挑选出比较好用的一款或几款&#xff0c;尽量满足界面精致、功能齐全、设置选项丰富的使用要求&#xff0c;便于节省一个个去尝试的时间和精力。 1. Chrome清理大师…

如何画架构图:从概念到实践

如何画架构图&#xff1a;从概念到实践 免费在线作图工具&#xff0c;点击邀请链接注册赠送7天会员&#xff1a;https://www.processon.com/u/5d3967afe4b0208611113845 在软件开发和系统设计中&#xff0c;架构图是一种重要的工具&#xff0c;它能够帮助开发人员和利益相关者…

嵌入式Qt 计算器核心算法_2

一.中缀表达式转后缀表达式 中缀表达式是最常用的算术表达式形式——运算符在运算数中间。但运算时需要考虑运算符优先级。 ​后缀表达式是计算机容易运算的表达式&#xff0c;运算符在运算数后面&#xff0c;从左到右进行运算,无需考虑优先级,运算呈线性结构。 1 2 * 3// …

打败茅台的“老酒”

作者&#xff1a;翻篇 琥珀酒研社快评&#xff1a; 最可恨的 从来不是什么强大敌人 而是美名其曰的猪队友 要不怎么有网友说 酒鬼酒太惨了 当年要不是败给内鬼 又曝出塑化剂事件 错过白酒发展的黄金十年 不说打败茅台、五粮液 但成为另一个茅台、五粮液 那完全有希…

Vue3_基础使用_4_路由器Router

概念&#xff1a; 路由&#xff1a;是一个key-value的对应关系叫路由。 路由器&#xff1a;管理多个路由的集合或者叫设备称为路由器。 由于现在组件替代了以前的mvc中的cshtml, 组件的菜单切换也不用我手动去写&#xff0c;vue给我们通过配置完成。 实现简单的路由跳转&…

10.vue学习笔记(组件数据传递-props回调函数子传父+透传Attributes+插槽slot)

文章目录 1.组件数据传递2.透传Attributes&#xff08;了解&#xff09;禁用Attributes继承 3.插槽slot 1.组件数据传递 我们之前讲解过了组件之间的数据传递&#xff0c;props 和 自定义事件 两种方式 props&#xff1a;父传子 自定义事件&#xff1a;子传父 props通过额外方…

通过eeprom验证FPGA实现的单字节/页读写IIC接口时序

1、概括 前文设计基于FPGA的IIC接口模块&#xff0c;本文将使用eeprom来验证该模块的设计。为了便于查看读写波形&#xff0c;采用两个按键来控制对eeprom数据的读写&#xff0c;当按键0按下后&#xff0c;FPGA向eeprom的前64个存储地址写入地址对应的数据&#xff0c;当按键1按…