文件系统
- 目录和文件(比如类似于ls的实现)
- 获取文件属性
- int stat(const char * path, struct stat *buf);// 获取文件信息,存储到buf中,返回成功失败,,面对符号链接文件时获取的是所指向的目标文件的属性
- lstat:面对符号链接文件时获取的是符号链接文件的属性,不对符号链接文件进行展开
- stat 命令同样可以查看文件的属性,通过文件路径
- fstat:通过文件描述符获取属性
- st_mode 文件类型,mode_t 16位整型数,9bits基本位,u+s g+s t+s 3位,七种文件类型, (& 0 被抹除 1 保留)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
static off_t flen(const char* fname)
{
struct stat res;
if (stat(fname, &res) < 0)
{
perror("stat");
exit(1);
}
return res.st_size; // off_t类型返回值
}
int main(int argc, char ** argv)
{
if (argc < 2)
{
fprintf(stderr, "usage\n");
exit(1);
}
printf("%lld\n", (long long)flen(argv[1]));
return 0;
}
// 查看文件类型
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
static int ftype(const char* fname)
{
struct stat res;
if (stat(fname, &res) < 0)
{
perror("stat");
exit(1);
}
if (S_ISREG(res.st_mode))
{
return '-'; // 常规文件
}
else if (S_ISDIR(res.st_mode))
{
return 'd'; // 目录文件
}
// 。。。
else
{
}
return '?';
}
int main(int argc, char ** argv)
{
if (argc < 2)
{
fprintf(stderr, "usage\n");
exit(1);
}
char c = ftype(argv[1]);
printf("%c\n", c);
return 0;
}
- 文件的访问权限问题: st_mode 是一个16位的位图,用于表示文件类型,文件访问权限,及特殊位
- umask:权限0666 & ~umask 目的是防止权限过松的文件
- chmod(const char * file, mode_t );
- fchmod
- 粘住位t位 把某一个命令使用痕迹保留 tmp目录就是t位
- 文件系统:fat ufs…
fat:静态单链表,分区,承载能力有限。缺点:单向
ufs:同一时代的产物
文件或数据的存储、管理 - 硬链接;同义词–特点:与目录项是的同义词,并建立硬链接有限制,不能给分区和目录建立
- 符号链接 ls -s (symble) inode与原来文件不相同 link(const char* old, const char * new path); 符号链接的优点是可以夸分区,可以给目录建立
- remove(const char * path); 删除一个文件
- rename(const char * oldchar, const char * new_path); 改变名字或改变位置
- utime:可以更改文件的最后读的时间和最后修改的时间
- 目录的创建和销毁:int mkdir(const char* pathname); int rmdir(const char * pathname);
- 更改当前工作路径 int chdir(const char * pathname); 修改进程的工作路径
- 分析目录、读取目录内容
glob(): 分析模式 解析模式/通配符 find pathnames matching a pattern
int glob(const char *pattern, int flags,
int (*errfunc) (const char *epath, int eerrno), // 保存出错路径出错 原因
glob_t *pglob); // 解析的结果存放 eg append 追加到pglob中
void globfree(glob_t *pglob); // 释放glob申请的空间
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 <stdlib.h>
#include <glob.h>
#define PAT "/etc/a*.conf"
// .* 是查找所有文件, /* 是查找文件, 不包括隐藏的
// glob 解析模式或者通配符
// int errfunc_(const char * errpath, int errno)
// {
// puts(errpath);
// fprintf(stderr, "error msg:%s\n", strerror(error));
// return 0;
// }
int main(int argc, char ** argv)
{
glob_t globalres;
// 解析etc下面的所有a开头的conf文件
int err = glob(PAT,0, NULL, &globalres);
if (err)
{
printf("error code = %d\n", err);
exit(1);
}
int i = 0;
for (i = 0; i < globalres.gl_pathc;i++)
{
puts(globalres.gl_pathv[i]);
}
globfree(&globalres)
return 0;
}
DIR* opendir(const char* name); 一对,打开的肯定在堆空间,后面会进行释放
closedir
#include <stdio.h>
#include <stdlib.h>
#include <glob.h>
#include <dirent.h>
#define PAT "/etc" // etc下面所有的文件 *代表pattern
int main()
{
DIR * dp = opendir(PAT);
struct dirent * cur;
if (dp == NULL)
{
perror("opendir");
exit(1);
}
while ((cur = readdir(dp)) != NULL)
{
puts(cur->d_name);
}
closedir();
return 0;
}
seekdir()
rewinddir
telldir()
du命令 当前路径所占的大小
du filename 文件的大小
du filename1 filename2 filename3 分析多个文件或路径所占的大小
// 实现一个du的命令
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <glob.h>
#include <string.h>
#define PATHSIZE 1024
static int path_noloop(const char* path)
{
char * pos = strrchr(path,'/'); // 右侧第一个/的位置
if (pos == NULL)
{
exit(1);
}
if (strcmp(pos + 1, ".") == 0 || strcmp(pos + 1, "..") == 0)
return 0;
return 1;
}
static int64_t mydu(const char* path)
{
// #if 0
// // path 为非目录
// st_blocks / 2
// return;
// // path 为目录文件
// path/*
// glob()
// stat()
// path/.*
// glob()
// #endif
// 如果一个变量完全出现在递归点之前或者递归点之后,可以将变量放在静态区,节省栈空间
static struct stat statres;
static char nextpath[PATHSIZE];
// 存在递归点中,使用auto存储
glob_t globres;
int64_t sum = 0;
int i;
if (lstat(path, &statres) < 0) // 获取文件属性,存放到statres中
{
perror("lstat");
exit(1);
}
if (!S_ISDIR(statres.st_mode)) // 文件是个dir
{
return statres.st_blocks;
}
// dir
strncpy(nextpath, path,PATHSIZE);
strncat(nextpath, "/*", PATHSIZE); // 拼接 路径/* 的所有文件
if (glob(nextpath, 0, NULL, &globres) < 0)
{
// 此时已经将所有非隐藏文件解析到res中
fprintf(stderr, "glob");
exit(1);
}
strncpy(nextpath, path, PATHSIZE);
strncat(nextpath, "/.*", PATHSIZE);
if (glob(nextpath , GLOB_APPEND , NULL, &globres) < 0)
{
// 解析隐藏文件,追加到res中
fprintf(stderr, "glob()");
exit(1);
}
sum = statres.st_blocks;
for (i = 0; i < globres.gl_pathc;i++)
// 没有. ..这种导致循环递归的情况需要进行递归,否则直接退
if(path_noloop(globres.gl_pathv[i]))
sum += mydu(globres.gl_pathv[i]);
// sum += statres.st_blocks;
globfree(&globres);
return sum;
}
int main(int argc, char** argv)
{
if (argc < 2)
{
fprintf(stderr, "usage");
exit(1);
}
printf("%lld\n", mydu(argv[1])/ 2);
return 0;
}
测试
du /etc/
mydu /etc