嵌入式 IO 4

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 //让配置文件生效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值