1.stat函数
1.1stat函数的介绍
int stat(const char *pathname, struct stat *statbuf);
功能:获取文件的属性信息(如果要获取软连接文件类型使用lstat函数)
参数:
@pathname:文件路径及名字
@statbuf:获取到文件属性存放到这个statbuf中
struct stat {
dev_t st_dev; //磁盘的设备号(是内核识别设备驱动的唯一编号)
ino_t st_ino; //inode号
mode_t st_mode; //文件的类型和权限
S_IFMT 0170000 bit mask for the file type bit field
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
//判断文件类型
if((stat.st_mode & S_IFMT) ==S_IFREG){
printf("这是普通文件\n");
}
//输出文件的权限
printf("%#o\n",stat.st_mode & 0777);
nlink_t st_nlink; //硬链接数
uid_t st_uid; //用户的id
gid_t st_gid; //组的id
dev_t st_rdev; //只有设备文件才有这个设备号
off_t st_size; //文件的大小,单位是字节
blksize_t st_blksize; //文件系统的block的大小(512字节)
blkcnt_t st_blocks; //文件的大小,单位是block
struct timespec st_atim; //最后一次访问文件的时间
struct timespec st_mtim; //最后一次修改文件的时间
struct timespec st_ctim; //最后一次状态改变的时间
};
返回值:成功返回0,失败返回-1置位错误码
1.2通过stat获取文件的属性实例
#include <head.h>
int main(int argc, const char* argv[])
{
struct stat st;
if (argc != 2) {
fprintf(stderr, "input error,try again\n");
fprintf(stderr, "usage: ./a.out filename\n");
return -1;
}
if(stat(argv[1],&st))
PRINT_ERR("get file stat error");
switch(st.st_mode & S_IFMT){
case S_IFREG:
printf("这是一个普通文件\n");
break;
}
printf("mode = %#o,inode = %ld,hardlink=%ld,size=%ld,uid=%d,gid=%d\n",
st.st_mode & 0777,st.st_ino,st.st_nlink,st.st_size,st.st_uid,st.st_gid);
return 0;
}
1.3getpwuid/getgrgid函数使用
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
功能:根据uid获取passwd结构体
参数:
@uid:用户的id
返回值:成功返回passwd的结构体指针,失败返回NULL,置位错误码
struct passwd {
char *pw_name; //用户名
char *pw_passwd; //密码
uid_t pw_uid; //uid
gid_t pw_gid; //gid
char *pw_gecos; //用户信息
char *pw_dir; //用户主目录
char *pw_shell; //命令行解析器 /bin/bash
};
#include <grp.h>
struct group *getgrgid(gid_t gid);
功能:根据组id获取group结构体
参数:
@gid:组id
返回值:成功返回group结构体指针,失败返回NULL,置位错误码
struct group {
char *gr_name; //组名
char *gr_passwd; //组的密码
gid_t gr_gid; //组id
char **gr_mem; //组内的成员
};
1.4getpwuid/getgrgid函数使用实例
#include <head.h>
int main(int argc, const char* argv[])
{
struct stat st;
struct tm* tm;
if (argc != 2) {
fprintf(stderr, "input error,try again\n");
fprintf(stderr, "usage: ./a.out filename\n");
return -1;
}
if (stat(argv[1], &st))
PRINT_ERR("get file stat error");
switch (st.st_mode & S_IFMT) {
case S_IFREG:
printf("这是一个普通文件\n");
break;
}
printf("mode = %#o,inode = %ld,hardlink=%ld,size=%ld,uname=%s,gname=%s\n",
st.st_mode & 0777, st.st_ino, st.st_nlink, st.st_size,
getpwuid(st.st_uid)->pw_name,
getgrgid(st.st_gid)->gr_name);
if ((tm = localtime(&st.st_atim.tv_sec)) == NULL)
PRINT_ERR("change time error");
printf("%d-%02d-%02d %02d:%02d:%02d\n", tm->tm_year + 1900,
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
return 0;
}
2.目录的操作
2.1opendir函数
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开目录
参数:
@name:目录名
返回值:成功返回目录的指针,失败返回NULL,并置位错误码
2.2readdir函数
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取目录下的内容
参数:
@dirp:目录的指针
返回值:成功返回dirent结构体指针,失败返回NULL置位错误码
struct dirent {
ino_t d_ino; //文件的inode号
unsigned short d_reclen; //结构体的大小
unsigned char d_type; //文件的类型
DT_BLK This is a block device.
DT_CHR This is a character device.
DT_DIR This is a directory.
DT_FIFO This is a named pipe (FIFO).
DT_LNK This is a symbolic link.
DT_REG This is a regular file.
DT_SOCK This is a UNIX domain socket.
DT_UNKNOWN The file type could not be determined.
char d_name[256]; //文件名
};
2.3closedir函数
int closedir(DIR *dirp);
功能:关闭目录
参数:
@dirp:目录的指针
返回值:成功返回0,失败返回-1置位错误码
2.4目录操作实例
#include <head.h>
int main(int argc, const char* argv[])
{
DIR* dir;
struct dirent* dt;
// 1.打开目录
if ((dir = opendir("./")) == NULL)
PRINT_ERR("open dir error");
// 2.读取目录下的文件
while ((dt = readdir(dir)) != NULL) {
printf("name=%s,ino = %ld,reclen=%d\n",
dt->d_name, dt->d_ino, dt->d_reclen);
switch (dt->d_type) {
case DT_BLK:
printf("这是块设备文件\n");
break;
case DT_CHR:
printf("这是字符设备文件\n");
break;
case DT_DIR:
printf("这是目录\n");
break;
case DT_FIFO:
printf("这是管道文件\n");
break;
case DT_LNK:
printf("这是软连接 文件\n");
break;
case DT_REG:
printf("这是普通文件\n");
break;
case DT_SOCK:
printf("这是套接字文件\n");
break;
default :
printf("这是未知文件类型\n");
}
}
//3.关闭目录
closedir(dir);
return 0;
}
2.5练习(目录和stat结合)
向程序输入一个文件名,程序判断(/home/linux/work/day4)目录下是否有这个文件,
如果这个文件存在将这个文件的信息显示出来(文件名字,类型,大小,
权限,最后一次被更改时间,用户和组)如果文件不存在就显示文件不存在,查询失败。
#include <head.h>
int main(int argc, const char* argv[])
{
DIR* dir;
struct dirent* dt;
struct stat st;
struct tm *tm;
char file[500] = { 0 };
// 0.请输入文件的名字
printf("input file > ");
fgets(file, sizeof(file), stdin);
file[strlen(file) - 1] = '\0';
// 1.打开目录
if ((dir = opendir("/home/linux/work/day3")) == NULL)
PRINT_ERR("open dir error");
// 2.读取目录下的文件
while ((dt = readdir(dir)) != NULL) {
if (strcmp(file, dt->d_name) == 0) {
//将文件的状态信息输出
snprintf(file, sizeof(file), "/home/linux/work/day3/%s", dt->d_name);
printf("%s\n",file);
//获取文件的属性信息
if ((stat(file, &st)))
PRINT_ERR("get file stat error");
//文件名字,类型,大小,权限,用户和组
printf("name=%s,type=%#o,mode=%#o,size=%ld,uname=%s,gname=%s\n",
dt->d_name, dt->d_type, st.st_mode & 0777, st.st_size,
getpwuid(st.st_uid)->pw_name,
getgrgid(st.st_gid)->gr_name);
//最后一次被更改时间
if ((tm = localtime(&st.st_atim.tv_sec)) == NULL)
PRINT_ERR("change time error");
printf("%d-%02d-%02d %02d:%02d:%02d\n", tm->tm_year + 1900,
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
return 0;
}
}
printf("查询的文件不存在,请重试\n");
// 3.关闭目录
closedir(dir);
return 0;
}
3.库的制作及使用
3.1库的简介
库文件:库文件是一个经过gcc编译生成的二进制文件,库文件能够保护工程师的程序代码。
库文件可以被其他的工程师使用,但是他看不到库中的代码实现。在制作库文件的时候对应
的.c源文件中不能有main函数。如果有main函数其他人无法使用。在linux系统上常用的库有
两种:静态库,动态库
静态库:lib库名.a
动态库:lib库名.so
3.2静态库
3.2.1静态库的特点
静态库文件的后缀是以.a结尾的文件,当用户需要使用这个静态库文件的时候,需要将他的.c
代码和libxxx.a的库文件编译生成一个可执行程序。这个可执行程序的体积比较大。但是执行的
效率比较高。当这个可执行程序执行的时候就不在需要这个libxx.a的库文件了。但是对于静态库
的更新比较麻烦。(可以通过ldd命令查看可执行程序链接的库)
3.2.2静态库的制作
gcc -c add.c -o add.o //只编译不链接
ar -cr libadd.a add.o //ar制作静态库的命令,-c 创建静态库 -r将函数放到库中
3.2.3静态库的使用
-L :库的路径
-l :链接库
-I :指定头文件的路径
gcc main.c -I ../inc/ -L ../lib/ -ladd -o ../bin/sum
3.3动态库
3.3.1动态库的特点
动态库文件的后缀是以.so结尾的文件,当用户需要使用这个动态库文件的时候,需要将他的.c
代码和libxxx.so文件中的函数符号表编译生成一个可执行程序。这个可执行程序的体积比较小。
但是执行的效率比较低。当这个可执行程序执行的时候就需要从这个库文件中找函数的实现。
但是对于动态库的更新比较方便。动态库又叫共享库。
3.3.2动态库的制作
gcc -fPIC -shared add.c -o libadd.so //将add.c编译生成libadd.so的动态库
//-fPIC:忽略文件位置 -shared 生成共享库
3.3.3动态库的使用
-L :库的路径
-l :链接库
-I :指定头文件的路径
gcc main.c -L ../lib/ -ladd -I ../inc/ -o ../bin/sum
3.3.4指定动态库的路径
注:如果不指定动态库的路径,执行会出现如下错误
方式一:通过库路径环境变量指定库的路径(临时生效)
export LD_LIBRARY_PATH=../lib (库的路径)
只在当前终端生效,如果关闭终端或者重启系统,这条命令就没有效果了。
方式二:将自己的动态库放到系统的/lib (永久有效)
sudo mv libadd.so /lib
方式三:通过修改系统配置文件让其生效(永久有效)
sudo vi /etc/ld.so.conf.d/libc.conf
sudo ldconfig //让配置文件生效