3.【多个IO知识点】

1. 文件IO和标准IO 对比

标准IO

文件IO

概念

C库定义的一组用于输入输出的函数

系统中定义的一组用于输入输出的函数

特点

1)有缓冲机制

2)围绕流进行操作,FILE *

3)只能操作普通文件

4)默认打开了三个流:stdout/stdin/stderr

1)无缓冲机制

2)围绕文件描述符操作,非负整数

3)默认打开了三个文件描述符:0/1/2

4)可以操作除目录文件 外的任意类型文件

函数

1)打开:fopen

2)关闭:fclose

3)读写:fgetc fputc fgets fputs fread fwrite

4)定位:rewind fseek ftell

1)打开:open

2)关闭:close

3)读写:read write

4)定位:lseek

linux下默认两者最多:能打开多少个文件:1024(最多打开1024个文件描述符)-3(默认打开的文件描述符)=1021

2. 目录操作

围绕目录流进行操作

opendir readdir closedir

DIR *opendir(const char *name);
功能:获得目录流
参数:要打开的目录
返回值:
	成功:目录流
    失败:NULL
----------------------------------------------

int closedir(DIR *dirp);
功能:关闭目录
参数:dirp:目录流
----------------------------------------------

struct dirent *readdir(DIR *dirp);
功能:读目录
参数:要读的目录流
返回值:
	成功:读到的信息(会每次读后更新偏移量)
    失败:NULL,设置errno号
	**返回值为结构体,该结构体成员为描述该目录下的文件信息**

struct dirent {
        ino_t   d_ino;               /* 索引节点号*/
        off_t   d_off;               /* 在目录文件中的偏移*/
        unsigned short d_reclen;     /* 文件名长度*/
        unsigned char  d_type;       /* 文件类型 */
        char    d_name[256];         /* 文件名 */
};

实现:ls功能

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>

int main(int argc, char *argv[])
{
    // 打开目录流
    DIR *dir = opendir("."); //.就是当前目录
    if (NULL == dir)
    {
        perror("dir open err");
        return -1;
    }
    puts("dir open err");

    // 存储 目录文件信息 的结构体
    struct dirent *d = NULL;

    // 每次读,都会更新 偏移量
    // 失败返回null(返回值为指针类型的函数,很多都如此)
    while ((d = readdir(dir)) != NULL)
    {
        // 不打印 隐藏文件
        if (d->d_name[0] != '.')
        {
            printf("name:%s\n", d->d_name);
            printf("name_len:%u\n", d->d_reclen);
            printf("file type:%u\n", d->d_type);

            printf("d_ino:%lu\n", d->d_ino);
            printf("off_t:%ld\n", d->d_off);
            puts("------");
        }
    }

    // 关闭目录流
    closedir(dir);
    // 置空 保存目录文件 的结构体指针
    d = NULL;
}

3. 文件属性获取

stat getpwuid getgugid ctime

3.1. stat 获取文件属性

int stat(const char *path, struct stat *buf);
功能:获取文件属性
参数:
	path:文件路径名
	buf: 保存文件属性信息的结构体
返回值:
	成功: 0
    失败:-1

// 各类属性,对应各自的方法  获取信息到 变量(如结构体)
struct stat {
        dev_t     st_dev;     /* 设备包含文件ID */
        ino_t     st_ino;     /* inode号 */
        mode_t    st_mode;    /* 文件类型和权限 */
        nlink_t   st_nlink;   /* 硬链接数 */
        uid_t     st_uid;     /* 用户ID */
        gid_t     st_gid;     /* 组ID */
        off_t     st_size;    /* 大小 */
        dev_t     st_rdev;    /* 设备ID */
        time_t    st_atime;   /* 最后访问时间 */
        time_t    st_mtime;   /* 最后修改时间 */
        time_t    st_ctime;   /* 最后状态改变时间 */
    };

3.1.1. 判断文件类型

3.1.2. 判断文件权限

简化写法 解释:

通过权限掩码,和对应位 相与,得到二进制进行判断

3.2. 获取 文件对应的:用户id 组id

struct passwd *getpwuid(uid_t uid);
功能:通过用户 id 获取用户属性
参数:uid:用户 id
返回值:
	成功:返回 保存用户相关属性的 结构体的地址
    失败:NULL

struct passwd
{
    char *pw_name;   /* 用户名 */
    char *pw_passwd; /* 密码 */
    uid_t pw_uid;    /* user ID */
    gid_t pw_gid;    /* group ID */
    char *pw_gecos;  /* 真实名 */
    char *pw_dir;    /* 主目录 */
    char *pw_shell;  /* 使用的shell */
};
struct group *getgrgid(gid_t gid);
功能:通过组 id 获取组属性
参数:gid:组 id
返回值:
	成功:返回保存组相关属性结构体的地址 
 	失败:NULL 

struct group
{
    char *gr_name;   /* 组名 */
    char *gr_passwd; /* 组密码 */
    gid_t gr_gid;    /* 组ID */
    char **gr_mem;   /* 组成员账号 */
};

3.3. 获取 文件时间戳

char *ctime(const time_t *timep);
功能:将时间秒数转化为字符串表示
参数:timep :时间
返回值:
	成功返回字符串首地址
	失败:NULL

3.4. 总体代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

void checkFileType(struct stat *st)
{
#if 0 //第一种写法
    switch (st->st_mode & __S_IFMT)
    {
    case __S_IFBLK:
        putchar('b');
        break;
    case __S_IFCHR:
        putchar('c');
        break;
    case __S_IFDIR:
        putchar('d');
        break;
    case __S_IFREG:
        putchar('-');
        break;
    case __S_IFLNK:
        putchar('l');
        break;
    case __S_IFSOCK:
        putchar('s');
        break;
    case __S_IFIFO:
        putchar('p');
        break;
    }
#else //第二种写法
    if (S_ISBLK(st->st_mode))
        putchar('b');
    else if (S_ISCHR(st->st_mode))
        putchar('c');
    else if (S_ISDIR(st->st_mode))
        putchar('d');
    else if (S_ISREG(st->st_mode))
        putchar('-');
    else if (S_ISLNK(st->st_mode))
        putchar('l');
    else if (S_ISSOCK(st->st_mode))
        putchar('s');
    else if (S_ISFIFO(st->st_mode))
        putchar('p');
#endif
}

void checkFilePermission(struct stat *st)
{
#if 0 //写法1
    char buf[3] = "rwx";
    for (int i = 0; i < 3; i++)
        st->st_mode &(0400) >> i ? printf("%c", buf[i % 3]) : putchar('-');

#else //写法2
    // 拥有者:挨个判断:读、写、可执行,不然就是无权限
    st->st_mode &S_IRUSR ? putchar('r') : putchar('-');
    st->st_mode &S_IWUSR ? putchar('w') : putchar('-');
    st->st_mode &S_IXUSR ? putchar('x') : putchar('-');

    // 组群用户者:挨个判断:读、写、可执行,不然就是无权限
    st->st_mode &S_IRGRP ? putchar('r') : putchar('-');
    st->st_mode &S_IWGRP ? putchar('w') : putchar('-');
    st->st_mode &S_IXGRP ? putchar('x') : putchar('-');

    // 其他用户看到后:挨个判断:读、写、可执行,不然就是无权限
    st->st_mode &S_IROTH ? putchar('r') : putchar('-');
    st->st_mode &S_IWOTH ? putchar('w') : putchar('-');
    st->st_mode &S_IXOTH ? putchar('x') : putchar('-');

#endif
}

int main(int argc, char *argv[])
{
    /* 先获取 目标文件的 信息结构体 */
    struct stat stat_buf;         //结构体变量
    if (stat(argv[1], &stat_buf)) //获取成功返回0,不然非0
    {
        perror("get file information err");
        return -1;
    }

    /* 文件类型的判断 */
    // 两种写法
    checkFileType(&stat_buf);

    /* 文件权限的判断 */
    // 两种写法
    checkFilePermission(&stat_buf);

    /* 该文件,硬链接的个数 */
    printf(" %d", stat_buf.st_nlink);

    /* 用户名 */
    printf(" %s", getpwuid(stat_buf.st_uid)->pw_name);

    /* 组名 */
    printf(" %s", getgrgid(stat_buf.st_gid)->gr_name);

    /* 文件 内存大小 */
    printf(" %ld", stat_buf.st_size);

    /* 最后修改时间 */
    // ctime:将时间秒数 转化为 字符串显示
    // +4 字符串首地址 后移
    // .12 右对其 12字符宽度
    printf(" %.12s", 4 + ctime(&stat_buf.st_mtime));

    /* 文件 名字 */
    printf(" %s\n", argv[1]);
}

4. 静态库 动态库

头文件:#include <> " "

源文件:xx.c

库文件:通俗来讲就是将用户写好的程序打包成一个整体,当其他模块或用户使用时,只需要有这个库文件就可以了,不需要源代码文件。也可以理解为一组预先编译好的方法的集合。

4.1. 概念

:就是把一些常用函数的目标文件打包在一起,提供相应函数的接口,便于程序员使用;本质上来说库是一种可执行代码的二进制形式

4.2. 库的分类

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

1) 静态库在程序编译时会被连接到目标代码中。

优点

程序运行时将不再需要该静态库;

运行时无需加载库,运行速度更快

缺点

静态库中的代码复制到了程序中,因此体积较大;

静态库升级后,程序需要重新编译链接

2) 动态库是在程序运行时才被载入代码中。

优点

程序在执行时加载动态库,代码体积小;

程序升级更简单;

不同应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

缺点

运行时还需要动态库的存在,移植性较差

4.3. 静态库的制作

  1. 将源文件编译生成目标文件

gcc -c xxx.c -o xxx.o

  1. 创建静态库,用ar命令,将许多.o文件生成.a文件

ar crs libxxx.a xxx.o

lib是库的前缀,xxx是库名 .a 是后缀

  1. 测试静态库的使用

gcc xxx.c -L指定库的路径 -l指定库名

./a.out

4.4. 动态库的制作

  1. gcc创建动态库

gcc -fPIC -c xxx.c -o xxx.o

-fPIC 创建与地址无关的编译程序

gcc -shared -o libxxx.so xxx.o

lib是库的前缀,xxx库名 .so动态库的后缀

  1. 测试动态库的使用

gcc xxx.c -L指定库的路径 -l指定库名

./a.out

4.4.1. 加载动态库的方法

可以正常编译通过,但是运行时报错./a.out: error while loading shared libraries: libmyadd.so: cannot open shared object file: No such file or directory

原因:

当加载动态库时,系统会默认从/lib或/usr/lib路径下查找库文件

解决方法(有三种):

(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 /etc/ld.so.conf.d/*.conf

添加动态库存在的路径,如:

/home/hq/work/teach/23061/day3/shared

刷新 sudo ldconfig

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值