Unix高级编程:获取文件元数据、文件夹操作

1. 计算机大小端,代码参见 big_little.c
#include <stdio.h>
int main(void) {
    short var_a = 0x0001;
    char *var_c = (char *)&var_a;
    if(*var_c) {
        printf("little ...\n");
    }   
    else
        printf("big ...\n");
    return 0;
}
2. 写一个函数实现strcpy字符串拷贝功能,代码参见 mystrcpy.c
char *t_strcpy(char *dest, const char *src);
返回值为什么是char *,而不是 void? "方便函数嵌套调用"用法2和3
char buf[12], buff[12];
t_strcpy(buf, "tarena"); //可能用法1
strlen(t_strcpy(buf, "tarena")); //可能用法2
t_strcpy(buff, t_strcpy(buf, "tarena")); //可能用法3,嵌套2次拷贝
#include <stdio.h>
#include <string.h> //strlen
//dest:值-结果参数
char *t_strcpy1(char *dest, const char *src) {
    char *p_tmp = dest;
    while(*p_tmp++ = *src++); //linux内核
    return dest;
}
char *t_strcpy2(char *dest, const char *src) {
    char *p_tmp = dest;
    while(*src = '\0') {
*p = *src;
p++, src++;
}
*p = *src; //或 *p = '\0';
    return dest;
}
int main(void) {
    char buf[12] = {0}, buff[12] = {0};
    char *s = "tarena";
    t_strcpy(buf, s); 
    printf("buf content: %s\n", buf);
    int size = strlen(t_strcpy(buf, s));//需要string.h
    printf("strlen(buf) = %d\n", size);
    t_strcpy(buff, t_strcpy(buf, s));
    printf("buff content: %s\n", buff);
    return 0;
}


一、获取文件的源数据
什么是文件元数据?
"文件的元数据"就是文件的属性。
文件有文件的"内容"和文件的"属性"。
[-][rw-][rw-][r--] 1 tarena tarena  489 12月  6 09:49 //mystrcpy.c
[1][234][567][890] (除了文件名以外,都是文件的属性,即文件的元数据)
[1]代表文件的类型:
"-" 普通文件 S_IFREG
"d" 文件夹文件 S_IFDIR
"c" 字符设备文件 S_IFCHR
"b" 块设备文件 S_IFBLK
"s" 通讯文件 S_IFSOCK
"l" 软链接文件 S_IFLNK
"p" 管道文件 S_IFIFO "?"


tarena(1) 属主,每个用户都有自己的身份证号,叫"uid"
属主的信息存放在" /etc/passwd/ "文件中
cat /etc/passwd
root:x:0:0:root:/root:/bin/bash //第一行
root 用户名
x 有密码标记,删除就无密码了
0 uid (可记)
0 gid
root 用户的简单备注说明
/root 用户工作的主目录,"~"是其简写
/bin/bash 用户启动的第一个程序bash


tarena(2) 属组,每个属组也有自己的身份证号,叫组id="gid"
属组的信息存放在" /etc/group/ "文件中
cat /etc/group


补充:
1)"stat"也可以查看文件的元数据
"格式:stat 文件名" //查看文件的元数据(属性)
2)链接文件
文件属性中的第一个 1 是硬链接数
每个文件都有且仅有一个自己的"inode"
但是一个inode可以对应多个文件的名字
"硬链接"的inode是同一个,"软链接"不是同一个(软链接也叫符号链接)。
链接的创建和使用
ln hello h //建立hello和h的硬链接,使用 stat hello 和 stat h查看
ln -s hello fileA //建立hello和fileA的软链接"fileA"->"hello"


通过系统调用获取文件的属性
"stat"(2)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
功能:获取文件的属性
参数:
"path" 文件路径,要获取属性的文件地址
"buf" 将文件的属性填充到buf指定的空间里
补充:
struct stat /*存放文件属性的结构体*/
struct stat {
   dev_t     st_dev;     /* 用于设备文件描述符 */ignore
   ino_t     st_ino;     /* inode号 */ 1
   mode_t    st_mode;    /* 类型/权限protection */ 1
   nlink_t   st_nlink;   /* 硬链接数 */ 1
   uid_t     st_uid;     /* 属主user ID */ 1
   gid_t     st_gid;     /* 属组组ID */ 1
   dev_t     st_rdev;    /* 设备文件ID */ignore
   off_t     st_size;    /* 总字节长度 */ 1
   blksize_t st_blksize; /* blocksize for file system I/O */ignore
   blkcnt_t  st_blocks;  /* number of 512B blocks allocated*/ignore
   time_t    st_atime;   /* 最后一次访问时间 */ 1
   time_t    st_mtime;   /* 最后修改时间 */ 1
   time_t    st_ctime;   /* 状态改变时间 */ 1
};
返回值:
成功 - 返回 0 
失败 - 返回 -1,errno被设置
/*举例验证,文件元数据的获取,代码参见 stat.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
int main(int argc, char *argv[]) {
    struct stat buf;
    int r = stat(argv[1], &buf); //获取文件的属性
    if(r == -1) { //stat函数调用失败
        perror("stat");
        return 1;
    }
    printf("stat success...\n");
    printf("inode number: %lu\n", buf.st_ino);
    printf("hard links: %d\n", buf.st_nlink);
    printf("total size: %ld\n", buf.st_size);
    printf("uid: %d\n", buf.st_uid);
    struct passwd *pass = getpwuid(buf.st_uid);
    if(pass == NULL) {
        printf("not found...\n");
        return 2;
    }
    printf("username: %s\n", pass->pw_name);
    printf("gid: %d\n", buf.st_gid);
    printf("time: %ld\n", buf.st_atime);
    printf("mode: %#o\n", buf.st_mode);
    if(S_ISREG(buf.st_mode)) {
        printf("-");
    }
    else if(S_ISDIR(buf.st_mode)) {
        printf("d");
    }
    printf("######################\n");
    switch(buf.st_mode & S_IFMT) { //做与操作
        case S_IFREG:
            printf("-");
            break;
        case S_IFDIR:
            printf("d");
            break;
        default:
            break;
    }
    printf("\n");
    if(buf.st_mode & S_IRUSR) {
        printf("r");
    } else
        printf("-");
    if(buf.st_mode & S_IWUSR) {
        printf("w");
    } else
        printf("-");
    if(buf.st_mode & S_IXUSR) {
        printf("x");
    } else
        printf("-");
    if(buf.st_mode & S_IRGRP) {
        printf("r");
    } else
        printf("-");
    if(buf.st_mode & S_IWGRP) {
        printf("w");
    } else
        printf("-");
    if(buf.st_mode & S_IXGRP) {
        printf("x");
    } else
        printf("-");
    if(buf.st_mode & S_IROTH) {
        printf("r");
    } else
        printf("-");
    if(buf.st_mode & S_IWOTH) {
        printf("w");
    } else
        printf("-");
    if(buf.st_mode & S_IXOTH) {
        printf("x");
    } else
        printf("-");
    printf("\n");
    return 0;
}


补充:
通过getpwnam(3)获取uid的名字
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
功能:获取uid相关信息
参数:"uid" 指定的uid
返回值:
成功 - 返回一个指向 struct passwd结构体类型的变量地址
失败 - 返回 NULL,没找到或有错误产生,如果是错误,errno被设置
struct passwd {
   char   *pw_name;       /* username */
   char   *pw_passwd;     /* user password */
   uid_t   pw_uid;        /* user ID */
   gid_t   pw_gid;        /* group ID */
   char   *pw_gecos;      /* user information */
   char   *pw_dir;        /* home directory */
   char   *pw_shell;      /* shell program */
};


通过getgrnam(3)获取gid的名字
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
功能:获取gid相关信息
参数:"gid"指定的gid
返回值:
成功 - 返回一个指向 struct group结构体类型的变量地址
失败 - 返回 NULL,没找到或有错误产生,如果是错误,errno被设置
struct group {
   char   *gr_name;       /* group name */
   char   *gr_passwd;     /* group password */
   gid_t   gr_gid;        /* group ID */
   char  **gr_mem;        /* group members */
};


使用ctime(3)将时间由数字转换为字符串类型时间显示
#include <time.h>
char *ctime(const time_t *timep);
功能:转换为日期和时间
参数:"timep" 指定的st_atime
返回值:
成功 - 返回时间值的描述
失败 - 返回 -1,errno被设置
struct tm {
   int tm_sec;         /* seconds */
   int tm_min;         /* minutes */
   int tm_hour;        /* hours */
   int tm_mday;        /* day of the month */
   int tm_mon;         /* month */
   int tm_year;        /* year */
   int tm_wday;        /* day of the week */
   int tm_yday;        /* day in the year */
   int tm_isdst;       /* daylight saving time */
};


二、文件夹的操作
drwxrwxr-x 3 tarena tarena 4096 12月  6 15:55 1206
"r" 读取文件夹的内容
"w" 更新文件夹的内容
"x" 文件夹是否允许你被通过(cd命令的是否成功)
文件夹的内容是文件夹里的文件


程序对文件夹的操作需要使用以下函数:
"opendir"(3)
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开一个文件夹
参数:"name" 指定了要打开的文件夹的名字
返回值:
成功 - 一个指向文件夹流的首地址的指针
失败 - 返回 NULL,errno被设置


"readdir"(3)
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取一个文件夹
参数:"dirp" opendir(3)的返回值,要读取内容的文件夹
返回值:
成功 - 返回一个结构体指针
失败 - 返回 NULL,到达文件末尾或者错误发生,如果是错误产生,errno被设置
struct dirent {
   ino_t          d_ino;       /* inode号 */
   off_t          d_off;       /* 下一个偏移两 */ ignore
   unsigned short d_reclen;    /* 记录长度 */ ignore
   unsigned char  d_type;      /* 不被所有文件支持 */ ignore
   char           d_name[256]; /* 文件名filename */
};


"closedir"(3)
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭一个文件夹
参数:"dirp" opendir(3)的返回值
返回值:
成功 - 返回 0
失败 - 失败 -1,errno被设置
/*举例验证,代码参见 dir_os.c*/
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
    DIR *p_dir = opendir(argv[1]);//打开命令行指定的文件夹
    if(!p_dir) {
        perror("opendir");
        return 1;
    }   
    printf("opendir success...\n");
    struct dirent *p_dire; 
//显示文件夹内所有文件inode和文件名
    while((p_dire = readdir(p_dir))) { 
/*if(!p_dire) {
perror("readdir");
return 2;
}*/
        printf("inode: %lu ", p_dire->d_ino);
        printf("filename: %s\n", p_dire->d_name);
    }
    closedir(p_dir);//关闭文件夹
    return 0;
}


"rewinddir"(3)
#include <sys/types.h>
#include <dirent.h>
void rewinddir(DIR *dirp);
功能:重置文件夹流到文件夹的开始位置
参数:"dirp" opendir(3)的返回值
返回值:无返回值。


"telldir"(3)
#include <dirent.h>
long telldir(DIR *dirp);
功能:当前文件夹流的位置
参数:"dirp" opendir(3)的返回值
返回值:
成功 - 返回当前文件夹流的位置
失败 - 返回 -1,errno被设置
/* 举例验证,代码参见 loca_dir.c */
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
    DIR *p_dir = opendir(argv[1]);//打开命令行指定的文件夹
    if(!p_dir) {
        perror("opendir");
        return 1;
    }   
    printf("opendir success...\n");
    long loc = telldir(p_dir);
    printf("p_dir location: %ld\n", loc);//打印文件夹里内容当前位置
    loc += 1; //当前位置向后移动两个文件
    printf("p_dir location: %ld\n", loc);
    struct dirent *p_dire = readdir(p_dir);
    printf("filename: %s\n", p_dire->d_name);
    rewinddir(p_dir);
    loc = telldir(p_dir);
    printf("p_dir location: %ld\n", loc);
    printf("filename: %s\n", p_dire->d_name);//问题:移动后文件没变?
    closedir(p_dir);//关闭文件夹
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姜源Jerry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值