文章目录
- 获取文件属性
- 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
动态库只需要重新生成动态库,不需要重新编译。
静态库需要重新编译