文件和目录
一、stat()
描述:把文件pathname的属性填入到结构体buf中
手册:man 2 stat
注意:stat与lstat区别
stat:
展开符号链接,回填的是符号链接所指向的文件的属性
fstat:
回填的是所打开文件的文件属性
lstat:
不展开符号链接,回填的是符号链接本身的文件属性
头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
函数原型:
int stat(const char *pathname, struct stat *buf);
-
pathname – 想要获取的文件
-
statbuf – 一个要回填的struct stat结构体类型的指针
成员 | 含义 |
---|---|
dev_t st_dev | 存的是文件本身存储设备的设备号,也就是硬盘的设备号 |
ino_t st_ino | inode索引号 |
mode_t st_mode | 文件类型(权限) |
nlink_t st_nlink | 硬链接 |
uid_t st_uid | 所有者ID |
gid_t st_gid | 组ID |
dev_t st_rdev | 是针对驱动的字符设备和块设备文件的主次设备号 |
off_t st_size | 总文件大小 |
blksize_t st_blksize | 当前文件系统中每一数据块的大小 |
blkcnt_t st_blocks | 当前文件占了多少512字节的块 |
struct timespec st_atim | 文件上一次打开的时间 |
struct timespec st_mtim | 文件内容上一次变动的时间 |
struct timespec st_ctim | inode 上一次变动的时间 |
查看结构体:man 2 stat
struct stat
{
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision 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
};
注意:
off_t st_size; /* Total size, in bytes */ blksize_t st_blksize; /* Block size for filesystem I/O */ blkcnt_t st_blocks; /* Number of 512B blocks allocated */
三个结构体成员没有任何关系
size只是一个属性而已
说明文件大小与文件磁盘上所占空间没有任何关系
返回值:
成功:0
失败:-1,设置errno
代码演示:
功能:获取文件大小
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
off_t flen(const char *fname)
{
struct stat statres;
if(stat(fname,&statres) < 0)
{
perror("stat()");
exit(1);
}
return statres.st_size;
}
int main(int argc,char *argv[])
{
if(argc < 2)
{
fprintf(stderr,"Usage:%s file\n",argv[0]);
exit(1);
}
printf("%lld\n",(long long)flen(argv[1]));
exit(0);
}
功能:证明文件大小与文件磁盘上所占空间的关系
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
int fd;
if(argc < 2)
{
fprintf(stderr,"Usage:%s file\n",argv[0]);
exit(1);
}
fd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0600);
if(fd < 0)
{
perror("open()");
exit(1);
}
/*生成5G大小的空洞文件,要加单位LL*/
lseek(fd,1024LL*1024LL*1024LL*5LL-1LL,SEEK_SET);
write(fd,"",1);
close(fd);
exit(0);
}
功能:获取文件类型
手册:man inode
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int ftype(const char *fname)
{
struct stat statres;
if(stat(fname,&statres) < 0)
{
perror("stat()");
exit(1);
}
if(S_ISREG(statres.st_mode))
return '-';
else if(S_ISDIR(statres.st_mode))
return 'd';
else
return '?';
}
int main(int argc,char *argv[])
{
if(argc < 2)
{
fprintf(stderr,"Usage:%s file\n",argv[0]);
exit(1);
}
printf("%c\n",ftype(argv[1]));
exit(0);
}
拓展
工具:ctags
默认安装 > /usr/include
作用:查看定义类型的原型
用法:vim -t ssize_t
在包含头文件前需要定义宏时两种方式
方式一:
命令行:gcc -D_ FILE_OFFSET_BITS =64 flen.c
-D:在命令行定义宏
方式二:
编译选项:CFLAGS += -D_ FILE_OFFSET_BITS =64
在makefile中
命令du:打印文件在磁盘中真正所占空间大小
例题:写一个程序,功能:实现du的功能
代码演示:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <glob.h> #include <stdint.h> #define PATHSIZE 1024 int path_no_loop(const char *path) {// ../io/..a /etc/. mydir/.. /etc/a/b/c/d/..a char *pos; pos = strrchr(path,'/'); if(strcmp(pos+1,".") == 0 || strcmp(pos+1,"..") == 0) return 0; return 1; } int64_t mydu(const char *path) { int i; struct stat statres; char nextpath[PATHSIZE]; glob_t globres; int64_t sum = 0; if(lstat(path,&statres) < 0) { perror("lstat()"); exit(1); } // not a dir if(!S_ISDIR(statres.st_mode)) return statres.st_blocks; // is a dir path = "../io" "/etc" "mydir" strncpy(nextpath,path,PATHSIZE); strncat(nextpath,"/*",PATHSIZE); glob(nextpath,0,NULL,&globres); strncpy(nextpath,path,PATHSIZE); strncat(nextpath,"/.*",PATHSIZE); glob(nextpath,GLOB_APPEND,NULL,&globres); for(i = 0 ; i < globres.gl_pathc; i++) { if(path_no_loop(globres.gl_pathv[i])) sum += mydu(globres.gl_pathv[i]); } sum += statres.st_blocks; return sum; } int main(int argc,char *argv[]) { glob_t globres; int i,err; if(argc < 2) { fprintf(stderr,"Usage:%s file\n",argv[0]); exit(1); } printf("TOTAL:%lld\n",(long long)mydu(argv[1])/2); exit(0); }
阅读:4.13文件截断truncate()
面试题:写一个程序,功能:删除一个文本文件的第10行
伪码:
fd1 = open(r); fd2 = open(r+); len (10); len(total) seek->fd1->11 seek->fd2->10 while() { read(fd1) write(fd2); } truncate(total-10);
代码演示
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define PATH "srcfile.log" #define SIZE 128 int main() { FILE *fd1,*fd2; off_t total; char buf[SIZE]; char buff[SIZE]; size_t len=0; int i=0,sum=0; fd1 = fopen(PATH,"r"); fd2 = fopen(PATH,"r+"); fseek(fd1,0,SEEK_END); total = ftell(fd1); rewind(fd1); while(i<10) { if(fgets(buf,SIZE,fd2) == NULL) break; sum += strlen(buf);//保存前十行 i++; } if(i<10) { printf("不足10行\n"); return -1; } fseek(fd1,sum,SEEK_SET);//第十一行 fseek(fd2,-strlen(buf),SEEK_CUR);//第十行行首 while(fgets(buff,SIZE,fd1) != NULL) { fputs(buff,fd2); } truncate(PATH,total-strlen(buf)); }
二、glob()
描述:用来匹配通配符指定模式的文本值
手册:man 3 glob
头文件:
#include <glob.h>
函数原型:
int glob(const char *pattern, int flags,
int (*errfunc) (const char *epath, int eerrno),
glob_t *pglob);
void globfree(glob_t *pglob);
-
pattern – 要解析的通配符
-
flags – 特殊要求(没有要求填0)
-
int (*errfunc) (const char *epath, int eerrno) – 自己构建函数,说明出错的详细信息(不需要填NULL)
-
pglob – 存放结果的空间
出错信息用法:
int myerrfun(const char *epath, int eerrno)
{
fprintf(stderr,"%s:%s\n",epath,strerror(eerrno);
}
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
成员 | 含义 |
---|---|
size_t gl_pathc | 计数器(类似man函数的argc) |
char **gl_pathv | 存放结果的数组(类似man函数的argv) |
常用特殊要求:
GLOB_APPEND(追加)
GLOB_NOCHACK(不检查文件名是否存在,直接将字符串存入结构体)
返回值:
成功:0
失败:非零(各种宏)
GLOB_NOSPACE
for running out of memory,
GLOB_ABORTED
for a read error, and
GLOB_NOMATCH
for no found matches.
代码演示:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <glob.h>
#define PAT "/etc/a*.conf"
int myerrfun(const char *epath, int eerrno)
{
fprintf(stderr,"%s:%s\n",epath,strerror(eerrno);
}
int main()
{
glob_t globres;
int i,err;
err = glob(PAT, 0, NULL/*myerrfun*/, &globres);
if(err)
{
printf("ERROR CODE:%d\n",err);
exit(1);
}
for(i = 0 ; i < globres.gl_pathc ; i++)
{
puts(globres.gl_pathv[i]);
}
globfree(&globres);
exit(0);
}
三、opendir()
描述:打开一个目录
手册:man 3 opendir
头文件:
#include <sys/types.h>
#include <dirent.h>
函数原型:
DIR *opendir(const char *name);
- name – 目录路径名
返回值:
成功:返回目录指针
失败:空指针,设置errno
代码演示:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#define PATH "/etc"
int main()
{
DIR *dp;
struct dirent *cur;
dp = opendir(PATH);
if(dp == NULL)
{
perror("opendir()");
exit(1);
}
while((cur = readdir(dp)) != NULL)
{
puts(cur->d_name);
}
closedir(dp);
exit(0);
}
四、getcwd()
描述:会将当前工作目录的绝对路径复制到参数buf所指的内存空间中,参数size为buf的空间大小
手册:man getcwd
头文件:
#include <unistd.h>
函数原型:
char *getcwd(char *buf, size_t size);
-
buf – 所要存绝对路径的数组空间
-
size – 数组的大小
返回值:
成功:返回当前工作目录绝对路径
失败:返回 NULL,设置errno
五、getpwuid() & getpwnam()
描述:将文件或目录拥有者的uid号或拥有者名字传入函数中,将其信息保存到结构体passwd中
手册:man getpwuid
头文件:
#include <sys/types.h>
#include <pwd.h>
函数原型:
struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);
- name – 文件或目录拥有者的名字
- uid – 文件或目录拥有者uid号
返回值:
成功:passwd结构体指针
失败:空指针
结构体
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 */
};
六、getgrgid() & getgrnam()
描述:将文件或目录所属组的gid号或组名传入函数中,将其信息保存到结构体group中
手册:man getgrgid
头文件:
#include <sys/types.h>
#include <grp.h>
函数原型:
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);
- name – 文件或目录所属的组名
- gid – 文件或目录的gid号
返回值:
成功:group结构体指针
失败:空指针
结构体
struct group
{
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
代码演示:
功能:将uid转换拥有者名。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
int main(int argc,char *argv[])
{
struct passwd *pwdline;
if(argc < 2)
{
fprintf(stderr,"Usage:%s file\n",argv[0]);
exit(1);
}
pwdline = getpwuid(atoi(argv[1]));//atoi():将字符串转化成整型,返回对应uid的结构体
if(pwdline == NULL)
{
perror("getpwuid()");
exit(1);
}
puts(pwdline->pw_name);
exit(0);
}