stat()函数解析

在完成任务的过程中遇到了一个问题就是调用stat函数获取文件信息的时候有些文件总是返回错误代码22(EVAL),后来一步一步跟踪到内核源码里面发现原来是文件名的长度超出了规定的长度。

因为是在nuttx上使用的该系统调用,所以以为是不是其中有bug,最后才知道是配置文件.config中配置CONFIG_FAT_MAXNAME为32太小了。之前也没有了解过该系统调用,所以就来仔细的看一看这个函数。

int stat(FAR const char *path, FAR struct stat *buf)

struct inode *inode_find(FAR const char *path, FAR const char **relpath)

首先根据路径名查找到相应的inode,inode是文件系统存放文件的一种形式,最小单位是扇区(sector),多个扇区集合成一个节点,节点分为文件信息节点和文件数据节点,注意的是一个目录名单独存放在一个节点中,linux中ext2/3/4文件系统都有这样的一种概念。

需要注意的是每一个节点都有9个标志位,有三组,每组中有3个标志位,分别表示可读,可写,可执行。

struct inode
  {
    FAR struct inode *i_peer;     /* Link to same level inode */
    FAR struct inode *i_child;    /* Link to lower level inode */
    int16_t           i_crefs;    /* References to inode */
    uint16_t          i_flags;    /* Flags for inode */
    union inode_ops_u u;          /* Inode operations */
  #ifdef CONFIG_FILE_MODE
    mode_t            i_mode;     /* Access mode flags */
  #endif
    FAR void         *i_private;  /* Per inode driver private data */
    char              i_name[1];  /* Name of inode (variable) */
  #ifdef CONFIG_SECURITY_IDMAC
    void             *i_security;
  #endif
  };

上面是nuttx中inode的数据结构,比linux中的inode数据结构简单很多,看了结构体中的内容可以看到其中肯定有链表的操作,而对文件操作则i_mode,注意i_mode的初始化操作是在mount操作,根据不同的文件系统格式来注册相应的回调函数。

static FAR const struct mountpt_operations *
 mount_findfs(FAR const struct fsmap_t *fstab, FAR const char *filesystemtype)

因为我使用的vfat格式的文件系统所以相应的回调函数是:

  const struct mountpt_operations fat_operations =
  {
    fat_open,          /* open */
    fat_close,         /* close */
    fat_read,          /* read */
    fat_write,         /* write */
    fat_seek,          /* seek */ 
    fat_ioctl,         /* ioctl */
  
    fat_sync,          /* sync */
    fat_dup,           /* dup */
     
    fat_opendir,       /* opendir */
    NULL,              /* closedir */
    fat_readdir,       /* readdir */
    fat_rewinddir,     /* rewinddir */
  
    fat_bind,          /* bind */
    fat_unbind,        /* unbind */
    fat_statfs,        /* statfs */
  
    fat_unlink,        /* unlinke */
    fat_mkdir,         /* mkdir */
    fat_rmdir,         /* rmdir */
    fat_rename,        /* rename */
    fat_stat           /* stat */
  };


在inode_find函数中最核心的函数是inode_search()。


FAR struct inode *inode_search(FAR const char **path,
                                FAR struct inode **peer,
                                FAR struct inode **parent,
                                FAR const char **relpath);
该函数根据文件名字依次一个一个寻找有相应的名字的inode(这里面就涉及了链表操作),并且返回。

找到相应的inode之后,就要执行一个相对中重要的函数

if (inode->u.i_mops && inode->u.i_mops->stat)
         {
           /* Perform the stat() operation */
 
           ret = inode->u.i_mops->stat(inode, relpath, buf);
         }
所以这里也就要调用之前已经注册好的vfat的相应stat回调函数。

static int fat_stat(FAR struct inode *mountpt, FAR const char *relpath,
                     FAR struct stat *buf);

该函数主要是找到相应的文件,并且把相应的文件信息填充到stat 结构体中

struct stat
 {
   mode_t    st_mode;    /* File type, atributes, and access mode bits */
   off_t     st_size;    /* Size of file/directory, in bytes */
   blksize_t st_blksize; /* Blocksize used for filesystem I/O */
   blkcnt_t  st_blocks;  /* Number of blocks allocated */
   time_t    st_atime;   /* Time of last access */
   time_t    st_mtime;   /* Time of last modification */
   time_t    st_ctime;   /* Time of last status change */
 };
在该函数中,比较重要的是

int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
                      const char *path);

而在这个函数中核心函数又是

static int fat_path2dirname(const char **path, struct fat_dirinfo_s *dirinfo,
                             char *terminator);


终于我们来到了最fat文件系统解析文件的最核心的函数了fat_parsesfname


Name: fat_parsesfname
  *
  * Desciption:  Convert a user filename into a properly formatted FAT
  *   (short 8.3) filename as it would appear in a directory entry.  Here are
  *    the rules for the 8+3 short file name in the directory:
  *
  *   The first byte:
  *
  *     0xe5 = The directory is free
  *     0x00 = This directory and all following directories are free
  *     0x05 = Really 0xe5
  *     0x20 = May NOT be ' '
  *
  *   Other characters may be any characters except for the following:
  *
  *     0x00-0x1f = (except for 0x00 and 0x05 in the first byte)
  *     0x22      = '"'
  *     0x2a-0x2c = '*', '+', ','
  *     0x2e-0x2f = '.', '/'
  *     0x3a-0x3f = ':', ';', '<', '=', '>', '?'
  *     0x5b-0x5d = '[', '\\', ;]'
  *     0x7c      = '|'
  *
  *   '.' May only occur once within string and only within the first 9
  *   bytes.  The '.' is not save in the directory, but is implicit in
  *   8+3 format.
  *
  *   Lower case characters are not allowed in directory names (without some
  *   poorly documented operations on the NTRes directory byte).  Lower case
  *   codes may represent different characters in other character sets ("DOS
  *   code pages".  The logic below does not, at present, support any other
  *   character sets.
  *
static inline int fat_parsesfname(const char **path,
                                   struct fat_dirinfo_s *dirinfo,
                                   char *terminator);

该函数会判断是不是可打印的字符,是不是被fat文件系统禁止的字符。

下面是nuttx中inode的数据结构,比linux中的inode数据结构简单很多,看了结构体中的内容可以看到其中肯定有链表的操作,而对文件操作则i_mode。
static inline int fat_parselfname(const char **path,
                                   struct fat_dirinfo_s *dirinfo,
                                   char *terminator)
该函数就是之前一直卡住我的问题,路径长度已经超过了事先定义好的长度。

当该路径名字符和fat文件系统的标准,之后就开始填充struct stat结构体了。


下面是nuttx中inode的数据结构,比linux中的inode数据结构简单很多,看了结构体中的内容可以看到其中肯定有链表的操作,而对文件操作则i_mode。
### stat_summary 函数概述 `stat_summary()` 是 `ggplot2` 中的一个重要函数,用于对数据进行汇总并将其结果显示在图形中。它允许用户通过指定不同的汇总函数来计算统计数据,并将这些统计数据显示为几何对象(如点、线条或文本)。该函数的主要用途是对分组后的数据应用自定义的统计摘要。 其基本语法如下: ```r stat_summary(mapping = NULL, data = NULL, geom = "pointrange", fun.data = NULL, fun.y = NULL, fun.ymax = NULL, fun.ymin = NULL, fun.args = list(), ...) ``` #### 参数说明 - **mapping**: 定义 aesthetic 映射。 - **data**: 数据框,默认继承父级 ggplot 的数据。 - **geom**: 指定使用的几何对象类型(默认为 `"pointrange"`)。 - **fun.data**: 提供一个返回多个值的函数,通常是一个列表结构的数据摘要函数。 - **fun.y**, **fun.ymax**, **fun.ymin**: 单独提供最小值、最大值和中间值的函数。 - **fun.args**: 向上述函数传递额外参数的列表。 - **...**: 其他传递给层的参数。 --- ### 示例代码解析 以下是一些常见的 `stat_summary()` 使用场景及其对应的代码实现。 #### 场景一:显示每组的样本数量 此功能可以通过设置 `fun.data = "n"` 来实现,其中 `n` 表示样本的数量[^1]。 ```r library(ggplot2) data(mtcars) p <- ggplot(mtcars, aes(x = factor(cyl), y = mpg)) p <- p + geom_point() p <- p + stat_summary( fun.data = "n", geom = "text", vjust = -1, aes(label = ..n..), size = 3 ) print(p) ``` 在此例子中,`factor(cyl)` 将 `cyl` 转换为因子变量以便按组分类,而 `aes(label = ..n..)` 则动态生成标签以展示每组中的样本数目。 --- #### 场景二:添加均值标记到箱线图 可以利用 `stat_summary()` 添加平均值或其他统计量作为附加信息到现有图表上[^4]。 ```r # 创建数据集 names <- c(rep("A", 20), rep("B", 8), rep("C", 30), rep("D", 80)) value <- c(sample(2:5, 20, replace = TRUE), sample(4:10, 8, replace = TRUE), sample(1:7, 30, replace = TRUE), sample(3:8, 80, replace = TRUE)) data <- data.frame(names, value) # 绘制带有均值点的箱线图 p <- ggplot(data, aes(x = names, y = value, fill = names)) + geom_boxplot(alpha = 0.7) + stat_summary(fun = "mean", geom = "point", shape = 20, size = 2.5, color = "red", fill = "red", alpha = 0.7) + theme(legend.position = "none") + scale_fill_brewer(palette = "Accent") print(p) ``` 这里使用了 `stat_summary()` 配合 `fun = "mean"` 计算各组的均值,并用红色圆圈表示出来。 --- #### 场景三:绘制误差棒 (Error Bars) 当需要表现数据分布的同时加入置信区间或者标准差时,可采用 `stat_summary()` 结合特定的几何对象完成这一目标[^3]。 ```r set.seed(123) df <- data.frame(group = rep(c("G1", "G2"), each = 10), values = rnorm(20, mean = 50, sd = 10)) p <- ggplot(df, aes(x = group, y = values)) + stat_summary(fun.data = mean_sdl, fun.args = list(mult = 1), geom = "crossbar", width = 0.5) + stat_summary(fun.y = mean, geom = "point", color = "blue", size = 3) print(p) ``` 在这个案例里,`mean_sdl` 自动计算均值以及上下限的标准偏差范围;随后分别用交叉条 (`crossbar`) 和蓝点标注结果。 --- ### 总结 `stat_summary()` 是一种灵活且强大的工具,在数据分析与可视化的流程中有广泛的应用价值。无论是简单的计数还是复杂的统计推断,都可以借助这个函数轻松达成目的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值