int stat(const char *pathname, struct stat *statbuf); //通过文件名 int fstat(int fd, struct stat *statbuf); //通过文件描述符 int lstat(const char *pathname, struct stat *statbuf); //在链接文件上处理不同
函数从pathname/fd这个文件中获取信息,存入statbuf结构体中
stat结构体内容如下:
struct stat { dev_t st_dev; //包含当前设备的文件的ID ino_t st_ino; //inode mode_t st_mode; //权限信息rwx nlink_t st_nlink; //硬链接数 uid_t st_uid; //userID gid_t st_gid; //groupID dev_t st_rdev; //设备的ID off_t st_size; //大小(单位字节) blksize_t st_blksize; //一个blocksize有多大,一般是512B blkcnt_t st_blocks; //当前这个文件占了多少个512字节的块 };
注意这里的size并不指文件的大小,只是一个属性,比如写一个10G的空洞文件,size是10G,但是占的空间只有几M。实际大小由blksize和blocks决定。
三个函数都是成功返回0,失败返回-1
stat结构体中的st_mode是个16位的位图,其中有文件类型的信息、文件访问权限以及特殊权限位,文件类型有dcb-lsp这七种,有七个宏用来看传入的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? S_ISSOCK(m) socket?
还有一个方法是让st_mode和另一个16位全1的位图相与,就可以得到st_mode实际是什么文件
switch (sb.st_mode & S_IFMT) { case S_IFBLK: printf("block device\n"); break; case S_IFCHR: printf("character device\n"); break; case S_IFDIR: printf("directory\n"); break; case S_IFIFO: printf("FIFO/pipe\n"); break; case S_IFLNK: printf("symlink\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFSOCK: printf("socket\n"); break; default: printf("unknown?\n"); break; }
创建文件后的默认属性是0666 & ~umask的值
举例
0666: 000 110 110 110
~umask(0022): 111 111 101 101
0666 & ~umask:000 110 100 100
即默认属性是rw-r–r--
umask的作用是防止产生权限过松的文件
命令的使用看chmod
在编程过程中需要临时一个文件的权限,可以使用函数的chmod
int chmod(const char *pathname, mode_t mode); int fchmod(int fd, mode_t mode); //使用样例 chmod(filename, 0700); chmod(fd, 0700);
原本用于给二进制执行文件在内存中保留其使用痕迹,现在cache的出现使得用处已经逐渐不大。现在常用于给目录设置t位
硬链接:用一个不同的名字关联源文件的inode,类似两个指针指向同一块内存。如果把源文件删了,另一个还能继续使用,只有链接计数归0才会真正删除文件。建立硬链接有限制:不能给分区建立,不能给目录建立
符号链接:相当于windows中的快捷方式,本身是独立的文件,拥有自己的inode,只不过文件内容是源文件的路径。如果删除源文件会导致符号链接失效。使用readlink
指令可以查看符号链接指向的文件。符号链接可跨分区,可给目录建立
这里提一下之前讲过的stat函数,其中有个lstat:
int lstat(const char *pathname, struct stat *statbuf);
如果给lstat函数传入的是符号链接文件,则获取的是符号链接文件的属性。而给stat传入符号链接文件,得到的是所指向的目标文件的属性
ln指令使用link函数实现的:
int link(const char *oldpath, const char *newpath); //创建newpath链接指向oldpath
还有个函数unlink:
int unlink(const char *pathname);
这个命令从文件系统中中删除一个名字,若这个名字是指向这个文件的最后一个链接,并且没有进程处于打开这个文件的状态,则删除这个文件,释放这个文件占用的空间,如果有进程打开这个文件,则要等到进程关闭这个文件之后才删除。如果这个名字指向一个符号链接,则删除这个符号链接。
cd是用chdir函数进行实现
int chdir(const char *path); int fchdir(int fd);
传入想切换去的路径
还有个函数用来获取当前工作路径
char *getcwd(char *buf, size_t size);
用于Linux文件系统中路径名称的模式匹配,即查找文件系统中指定模式的路径。
int glob(const char *pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob);
pattern是个通配符,描述一个文件路径的模式。
flag是或一些符号信息,有以下几个常用的:
第三个参数是一个函数指针,如果glob函数解析出错,将会把出错的路径和eerrno都传入这个函数。
第四个参数是一个结构体,内容如下:
typedef struct { size_t gl_pathc; //匹配到的路径数,类似argc char **gl_pathv; //匹配到的路径,类似argv size_t gl_offs; /* Slots to reserve in gl_pathv. */ } glob_t;
成功返回0,否则返回:
#define PAT "/etc/.*" #if 0 static int errfunc(const char *epath, int eerrno) { puts(epath); fprintf(stderr, "ERROR MSG: %s\n", strerror(eerrno)); return 0; } #endif int main(int argc, char *argv[]) { glob_t globres; int err = glob(PAT, GLOB_NOSORT, NULL, &globres); if (err) { printf("ERROR CODE: %d\n", err); exit(1); } for (int i = 0; i < globres.gl_pathc; i++) puts(globres.gl_pathv[i]); globfree(&globres); //别忘了释放 exit(0); }
像操作文件函数一样使用目录的函数
通过目录名打开/关闭一个目录流
DIR *opendir(const char *name); DIR *fdopendir(int fd); //open可以打开目录,也会得到一个描述符 //成功则返回目录流指针,否则返回空
int closedir(DIR *dirp);
用于读取一个目录
struct dirent *readdir(DIR *dirp);
返回一个结构体指针,存有目录的基本属性,该指针内容如下:
struct dirent { ino_t d_ino; /* Inode number */ off_t d_off; /* Not an offset; see below */ unsigned short d_reclen; /* Length of this record */ unsigned char d_type; /* Type of file; not supported by all filesystem types */ char d_name[256]; /* Null-terminated filename */ };