《LINUX系统编程》笔记p3

可重用函数

不使用全局部变量,可以重复使用的函数.

stat 命令

作用:显示一个文件或文件夹的“元信息”。

文件基本信息

  • 文件(File):显示所查询对象的名称。

  • 大小(Size):文件的大小,以字节为单位。

  • 块(Blocks):文件在磁盘上所占用的物理块数量(通常以 512字节 或 1K 的块为单位,取决于系统和 stat 的实现)。

  • IO 块(IO Block):文件系统每次读写操作的数据块大小。

  • 文件类型和索引节点(Inode)

    • 设备(Device):文件所在的设备标识符,通常以 主设备号,次设备号 的形式表示,指明了文件存储在哪个硬件设备上。
    • Inode:文件的索引节点号。Inode 是文件系统中存储文件元数据(除文件名外的一切信息)的数据结构。每个 Inode 号在同一个文件系统内是唯一的。
  • 文件类型(Filetype),例如:

    • 常规文件(regular file)
    • 目录(directory)
    • 符号链接(symbolic link)
    • 块设备(block device)
    • 字符设备(character device)
    • 套接字(socket)
    • 命名管道(FIFO)等。
  1. 权限和链接

    • 权限(Access):文件的访问权限,以数字(八进制,如 0644) 和类似 ls -l 的符号(如 -rw-r--r--) 两种形式显示。
    • 硬链接数(Links):指向该 Inode 的硬链接数量。对于目录,这个数字通常至少为 2(本身和其内部的 . 目录)。
      所有权信息
      UID / GID:文件所有者的用户ID(User ID)和组ID(Group ID)。
  2. 时间戳(Timestamps) - 这是 stat 命令最核心和详细的信息之一 它提供了三个精确到纳秒的时间戳,远比其他命令详细:

    • 访问时间(Access):文件内容最后一次被读取的时间(例如,
    • 修改时间(Modify):文件内容最后一次被修改的时间。
    • 变更时间(Change):文件的元数据(如权限、所有权、硬链接数等属性)最后一次被改变的时间。

stat 命令格式

stat [文件或文件夹]

stat 函数

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>// 使用文件路径获件的信息
int stat(const char *pathname, struct stat *statbuf);// 使用文件描述符获件的信息
int fstat(int fd, struct stat *statbuf);// lstat获取软链接文件本身的信息, stat获取文件的信息
int lstat(const char *pathname, struct stat *statbuf);

struct stat 结构体

struct stat {dev_t     st_dev;         /* ID of device containing file 设备文件ID */ino_t     st_ino;         /* Inode number 索引节点数*/mode_t    st_mode;        /* File type and mode 文件类型和模式 , st_mode. 的文件类型等信息,详见 inode(7):man 7 inode*/nlink_t   st_nlink;       /* Number of hard links 硬连接数*/uid_t     st_uid;         /* User ID of owner 拥有者ID*/gid_t     st_gid;         /* Group ID of owner 拥有者组ID*/dev_t     st_rdev;        /* Device ID (if special file)  设备ID */off_t     st_size;        /* Total size, in bytes 文件大小*/blksize_t st_blksize;     /* Block size for filesystem I/O 每次IO 的块大小 */blkcnt_t  st_blocks;      /* Number of 512B blocks allocated 以 512 字节计算的块数。*//* Since Linux 2.6, the kernel supports nanosecondprecision for the following timestamp fields.For the details before Linux 2.6, see NOTES. */struct timespec st_atim;  /* Time of last access 最后访问时间*/struct timespec st_mtim;  /* Time of last modification 最后修改时间 */struct timespec st_ctim;  /* Time of last status change 最后元数据块修改时间*/#define st_atime st_atim.tv_sec      /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};

st_mode 的类型掩码和值

// 类型掩码(4bit)
S_IFMT     0170000   bit mask for the file type b
it 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  管道文件
// 用法
strcut stat sb;
stat(pathname, &sb);
if ((sb.st_mode & S_IFMT) == S_IFREG) {/* Handle regular file */
}

判断 st_mode 是哪一类型文件的宏定义

S_ISREG(m)  is it a regular file?
S_ISDIR(m)  directory?
S_ISCHR(m)  character device?
S_ISBLK(m)  block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m)  symbolic     link?      (Not     inPOSIX.1-1996.)
S_ISSOCK(m) socket?  (Not in POSIX.1-1996.)
// 用法
struct stat sb;
stat(pathname, &sb);
if (S_ISREG(sb.st_mode)) {/* Handle regular file */
}

示例代码:

#include <time.h>int main(int argc, char * argv[]) {int ret;struct stat st;ret = stat("homework01.c", &st);// ret = stat("./test", &st);printf("文件大小:%ld\n", st.st_size);printf("文件块个数:%ld\n", st.st_blocks);printf("修改时间:%s\n", ctime(&st.st_mtim.tv_sec));// 判断stat 的第一个参数是什么类型的文件。switch (st.st_mode & S_IFMT) { // man 7 inode 查找宏定义case S_IFREG:printf("普通文件\n");break;case S_IFDIR:printf("文件夹\n");break;default:printf("其他类型的文件\n");}printf("程序结束\n");return 0;
}

时间函数

#include <time.h>// 将 struct tm 转为时间字符串。
char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);// 将 time_t 转为时间字符串,格式: Fri Aug 22 09:40:48 2025。
char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);

文件夹遍历

// 打开文件夹
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);// 遍历文件夹
#include <dirent.h>
struct dirent *readdir(DIR *dirp);// 关闭文件夹
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);

示例

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>int main(int argc, char * argv[]) {DIR *dir;struct dirent *curd;dir = opendir(".");while(curd = readdir(dir)) {// #define NULL ((void*)0)// printf("%p\n", curd);printf("curd->d_type:%#x, curd->d_name:%s\n", curd->d_type, curd->d_name);}closedir(dir);printf("程序结束\n");return 0;
}

glob 函数查找文件

作用:使用模式匹配解析文件夹内容。

匹配样式特殊字符

* 匹配0个一个或多个字符
? 匹配任意单个字符。
[a-z]  匹配一个某个范围内的字符。
[xyz]  匹配一个字符,这个字符必须是 x 或 y 或 z
[^xyz]  匹配一个字符,这个字符不能是 x 或 y 或 z

相关函数

#include <glob.h>// 获取模式匹配的路径信息,存入pglob。
int glob(const char *pattern, int flags,int (*errfunc) (const char *epath, int eerrno),glob_t *pglob);
// 参数:
// pattern 路径的样式
// flags 搜索的标志位(位或可以加入多个选项):GLOB_NOSORT 表示不排序,
// errfunc 错误回调函数,不用时置空
// pglob 解析到的目录个数以及各个文件名的数组。//释放glob函数动态开辟的空间
void globfree(glob_t *pglob);// 类型:
glob_t //存储解析到的目录个数以及各个文件名

glob_t 类型

 typedef struct {size_t   gl_pathc;    /* Count of paths matched so far  */char   **gl_pathv;    /* List of matched pathnames.  */size_t   gl_offs;     /* Slots to reserve in gl_pathv.  */
} glob_t;

示例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <dirent.h>
#include <glob.h>// 搜索 /etc/pass* 或 当前的"*.c" 文件
int main(int argc, char * argv[]) {glob_t gs; // 用于存储解析到的文件个数和文件名int i; // 循环变量int ret;ret = glob("/etc/pass*", GLOB_NOSORT, NULL, &gs);if (ret) {printf("glob error:%d\n", ret);}ret = glob("./0[0-9]*.c", GLOB_APPEND, NULL, &gs);// 循环打印遍历的结果。for (i = 0; i < gs.gl_pathc; i++) {printf("path: %s\n", gs.gl_pathv[i]);}// 释放glob 开辟的内存空间。globfree(&gs);printf("程序结束\n");return 0;
}

getopt 函数

作用:解析命令行选项【option】和参数【argument】

函数格式

#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring);

示例代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>// 命令选项: 
//    -f <文件路径>  文件路径可以通过 optarg 全局变量获取。
//    -c 创建 
//    -x 解压缩
int main(int argc, char * argv[]) {const char * optstring = "cxf:";int ret;  //用于接收返回的命令选项while (1) {ret = getopt(argc, argv, optstring);if (ret == -1) {  // 解析完毕break; // 结束循环}switch(ret) {case 'x': printf("-x 选项被输入\n");break;case 'c': printf("-c 选项被输入\n");break;case 'f': printf("-f  选项: %s\n", optarg);break;default:break;}}printf("程序结束\n");return 0;
}

密码加密

Linux 下保存密码的文件是:/etc/shadow

easthome 的密码信息:

easthome:$6$ISBgRfwrvZNBigDh$ynkvsffzGH2ovijtzar9CUiu37cTfx0SJcSs.TYWsXyVoJb1xFfmQX.PDyx5B0eU7mNZf0umcPI0ZvmpDf/dR/:20290:0:99999:7:::$6$ISBgRfwrvZNBigDh$ynkvsffzGH2ovijtzar9CUiu37cTfx0SJcSs.TYWsXyVoJb1xFfmQX.PDyx5B0eU7mNZf0umcPI0ZvmpDf/dR/

实现用户登陆之前的密码校验:

相关函数

// 获取密码函数
#include <unistd.h>
char *getpass(const char *prompt);// 根据加密算法和盐信息加密字符串 
// 使用 crypt 函数在编译时需要加载 libcrypt 库。 gcc -lcrypt
#include <crypt.h>
char * crypt(const char *phrase, const char *setting);
// 参数: 
//    phrase: 要加密的信息。
//    setting 加密算法和盐信息,格式为 "$加密算法$盐$"
// 返回值:
//    加密后的哈希字符串。// 读取/etc/shadow 密码信息
#include <shadow.h>
struct spwd *getspnam(const char *name);  // name 是用户名。
// 参数:
//     name 用户名
// 返回值:
//     shadow 中的加密算法、盐、和哈希字符串。

示例代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <shadow.h>
#include <crypt.h>
#include <string.h>#define MAX_NAME_SIZE (20)int main(int argc, char * argv[]) {char username[MAX_NAME_SIZE] = {}; // 用于存储用户名.char * pwd = NULL; // 用于指向用户输入的密码。struct spwd * tp = NULL; // 指向shadow文件中读出的信息。char * serial = NULL; // 事项加密后的哈希值(密码)。printf("请输入用户名:");fflush(stdout);int ret = read(0, username, MAX_NAME_SIZE);//int ret = fgets(username, MAX_NAME_SIZE, stdin);  // 此函数会读取回车符号username[ret-1] = '\0'; // 把 '\n' 替换成  '\0';// 读取密码pwd = getpass("请输入密码:");if (NULL == pwd) {perror("getpass");return -1;} // printf("username:%s, password:%s\n", username, pwd);// 读取系统内/etc/shadow真实的密码信息tp = getspnam(username);if (NULL == tp) {printf("获取shadow 密码失败\n");return -2;}//将输入的密码进行加密serial = crypt(pwd, tp->sp_pwdp); // 使用加密算法和盐进行加密。if (NULL == serial) {perror("crypt");return -3;} //对比生成的 serial 和 tp->sp_pwdp 是否相同。如果相同说明验证成功。if (0 == strcmp(tp->sp_pwdp, serial)) {printf("登陆成功\n");} else {printf("登陆失败\n");}printf("程序结束\n");return 0;
}

编译(加 -lcrypt 选项):

gcc 05_check_password.c -lcrypt

字符串分割

strtok 函数

作用:分割字符串

调用格式

#include <string.h>
char *strtok(char *str, const char *delim);
// 参数:
//   str 需要分割的字符串,第一次需要传入可变字符串,之后需要传入NULL
//   delim 分割的字符串
// 返回值: 返回分割的子字符串的起始地址,到达末尾时返回NULL。

字符串的内容:

"zhangsan,18,100"

示例代码

#include <stdio.h>
#include <string.h>// 分割字符串示例;
int main(int argc, char * argv[]) {char buffer[] = "zhangsan,18,100,1.73";char * str_head = buffer; //将str_head指向字符串的首地址char * str_ret;while(1) {str_ret = strtok(str_head, ","); if (NULL == str_ret)break;printf("str_ret:%s\n", str_ret);str_head = NULL;}// str_ret = strtok(str_head, ","); // printf("str_ret:%s\n", str_ret);// str_ret = strtok(NULL, ","); // printf("str_ret:%s\n", str_ret);// str_ret = strtok(NULL, ","); // printf("str_ret:%s\n", str_ret);printf("程序结束\n");return 0;
}

strsep 函数

调用格式

#include <string.h>
char *strsep(char **stringp, const char *delim);
// 参数
//   stringp 是指向字符串指针的地址。
//   delim 分割的字符串
// 返回值: 返回子字符串的起始地址,即*stringp。到达末尾时返回NULL。

示例代码

#include <stdio.h>
#include <string.h>// 分割字符串示例;
int main(int argc, char * argv[]) {char buffer[] = "zhangsan,18,100,1.73";char * str_head = buffer; //将str_head指向字符串的首地址char * str_ret;while(1) {str_ret = strsep(&str_head, ","); if (NULL == str_ret)break;printf("str_ret:%s\n", str_ret);}// str_ret = strsep(&str_head, ",");// printf("str_ret:%s\n", str_ret);// str_ret = strsep(&str_head, ",");// printf("str_ret:%s\n", str_ret);// str_ret = strsep(&str_head, ",");// printf("str_ret:%s\n", str_ret);printf("程序结束\n");return 0;
}

常量字符串不能用于上述两个函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/94263.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/94263.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型0基础开发入门与实践:第3章 机器的“统计学”:机器学习基础概念扫盲

第3章 机器的“统计学”&#xff1a;机器学习基础概念扫盲 1. 引言 想象一下&#xff0c;你是一位古代的农夫&#xff0c;毕生的经验告诉你&#xff1a;乌云密布、燕子低飞&#xff0c;那么不久便会下雨。你并没有学习过气象学&#xff0c;也不懂大气压和水汽凝结的原理。你的“…

Java调用Ollama(curl方式)

1. 安装Ollama Search 2. 调用 相关依赖 <dependencies><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.14</version></dependency><dependency>&…

nodejs koa框架使用

1: KOA 是express 打造的下一代web 开发框架提供更小更强的的核心功能&#xff0c;通过Promise 、async/await 进行异步编程&#xff0c;koa 可以不使用回调&#xff0c;解决了回调地狱的问题 blueBird 是nodejs 最出名的Primise 实现&#xff0c;除了实现标准的promise 之外&a…

2025年图像处理与光学国际会议(ICIPO 2025)

2025年图像处理与光学国际会议&#xff08;ICIPO 2025&#xff09; 2025 International Conference on Image Processing and Optics一、大会信息会议简称&#xff1a;ICIPO 2025 大会地点&#xff1a;中国北京 审稿通知&#xff1a;投稿后2-3日内通知 投稿邮箱&#xff1a;iac…

Kubernetes 构建高可用、高性能 Redis 集群

k8s下搭建Redis高可用1. 部署redis服务创建ConfigMap创建 Redis创建 k8s 集群外部2. 创建 Redis 集群自动创建 redis 集群手动创建 redis 集群验证集群状态3. 集群功能测试压力测试故障切换测试4. 安装管理客户端编辑资源清单部署 RedisInsight控制台初始化控制台概览实战环境使…

文件IO的基础操作

Java针对文件进行的操作:文件系统操作,File类(file类指定的路径,可以是一个不存在的文件)文件内容操作 : 流对象分为两类(1)字节流 以字节为基本的读写单位的 二进制文件 InputStream OutputStream(2)字符流 以字符为基本的读写单位的 …

【模版匹配】基于深度学习

基于深度学习的模版匹配 概述 本报告整理了2024-2025年最新的、可直接使用的模板匹配相关论文、方法和开源代码实现。所有方法都提供了完整的代码实现和预训练模型&#xff0c;可以直接应用到实际项目中。 一、轻量级现代模板匹配框架 1.1 UMatcher - 4M参数的紧凑型模板匹…

CMake进阶:Ninja环境搭建与加速项目构建

目录 1.引入Ninja的原因 2.Ninja 环境搭建&#xff08;跨平台&#xff09; 2.1.Linux系统安装 2.2.macOS 系统 2.3.Windows 系统 2.4.源码编译安装&#xff08;通用方案&#xff09; 3.Ninja 与构建系统配合&#xff1a;以 CMake 为例 4.加速构建的关键技巧 5.Ninja 与…

开发避坑指南(35):mybaits if标签test条件判断等号=解析异常解决方案

异常信息 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: The expression orderInfo.idList evaluated to a null value.报错语句 <if test"orderInfo.queryFlag ! null and orderInfo.queryFlag sett…

GitCode 疑难问题诊疗:全面指南与解决方案

引言 在软件开发的动态领域中&#xff0c;GitCode 作为一款强大的分布式版本控制系统&#xff0c;已然成为团队协作与项目管理的基石。它赋予开发者高效管理代码版本、轻松实现并行开发以及顺畅协同合作的能力。然而&#xff0c;如同任何复杂的技术工具&#xff0c;在 GitCode…

使用 JS 渲染页面并导出为PDF 常见问题与修复

本文直击两个最常见的导出痛点&#xff0c;并给出可直接落地的诊断 修复方案&#xff08;适用于 html2canvas jsPDF ECharts/自绘 canvas 场景&#xff09;。 问题清单 问题 A&#xff1a;导出后图表模糊&#xff0c;线条与文字不清晰&#xff08;低分辨率&#xff09;。问题…

【Java后端】【可直接落地的 Redis 分布式锁实现】

可直接落地的 Redis 分布式锁实现&#xff1a;包含最小可用版、生产可用版&#xff08;带 Lua 原子解锁、续期“看门狗”、自旋等待、可重入&#xff09;、以及基于注解AOP 的无侵入用法&#xff0c;最后还给出 Redisson 方案对比与踩坑清单。一、设计目标与约束 获取锁&#x…

数据结构 -- 链表--双向链表的特点、操作函数

双向链表的操作函数DouLink.c#include "DouLink.h" #include <stdio.h> #include <stdlib.h> #include <string.h>/*** brief 创建一个空的双向链表* * 动态分配双向链表管理结构的内存&#xff0c;并初始化头指针和节点计数* * return 成功返回指…

Wireshark获取数据传输的码元速率

一、Wireshark的物理层参数 Wireshark主界面可以看到数据发送时刻和长度&#xff1a; 这个时刻是Wireshark完整获取数据包的时刻&#xff0c;实际上就是结束时刻。 需要知道的是&#xff1a; Wireshark工作在数据链路层及以上&#xff0c;它能解码 以太网帧 / IP 包 / TCP…

11.1.3 完善注册登录,实现文件上传和展示

1、完善注册/登录 1. 涉及的数据库表单&#xff1a;user_info 2. 引用MySQL线程池&#xff0c;Redis线程池 3. 完善注册功能 4. 完善登录功能 2.1 涉及的数据库表单&#xff1a;user_info 重新创建数据库 #创建数据库 DROP DATABASE IF EXISTS 0voice_tuchuang;CREATE D…

【Linux文件系统】目录结构

有没有刚进入Linux世界时&#xff0c;对着黑乎乎的终端&#xff0c;输入一个 ls / 后&#xff0c;看着蹦出来的一堆名字 like bin, etc, usr&#xff0c;感觉一头雾水&#xff0c;像是在看天书&#xff1f; 别担心&#xff0c;你不是一个人。Linux的文件系统就像一个超级有条理…

螺旋槽曲面方程的数学建模与偏导数求解

螺旋槽曲面的数学描述 在钻头设计和机械加工领域,螺旋槽的几何建模至关重要。螺旋槽通常由径向截形绕轴做螺旋运动形成,其数学模型可通过参数方程和隐函数方程两种方式描述。 设螺旋槽的径向截形方程为: y=f(z)y = f(z)y=f(z) x=xcx = x_cx=xc​ 其中 xcx_cxc​ 为常数,…

线性回归:机器学习中的基石

在机器学习的众多算法中&#xff0c;线性回归无疑是最基础也是最常被提及的一种。它不仅在统计学中占有重要地位&#xff0c;而且在预测分析和数据建模中也发挥着关键作用。本文将深入探讨线性回归的基本概念、评估指标以及在实际问题中的应用&#xff0c;并通过一个模拟的气象…

编程刷题-资料分发1 图论/DFS

P2097 资料分发 1 题目描述 有一些电脑&#xff0c;一部分电脑有双向数据线连接。 如果一个电脑得到数据&#xff0c;它可以传送到的电脑都可以得到数据。 现在&#xff0c;你有这个数据&#xff0c;问你至少将其输入几台电脑&#xff0c;才能使所有电脑得到数据。 输入格式 第…

RabbitMQ:延时消息(死信交换机、延迟消息插件)

目录一、死信交换机【不推荐】二、延迟消息插件【推荐】2.1 安装插件【Linux】2.2 安装插件【Windows】2.3 如何使用延时消息&#xff1a;生产者发送消息时指定一个时间&#xff0c;消费者不会立刻收到消息&#xff0c;而是在指定时间之后才收到消息。 延时任务&#xff1a;设置…