unix下的文件和目录详解以及操作方法
前言:unix下一切东西都是文件,一共有7种不同的文件,前一篇博客已经讲解的很清楚了,不懂的可以看看这里。当然,博主知道有些朋友比忙,没时间看,那我就简单点讲讲这7种文件都有哪些吧。
文件类型包括在stat结构的st_mode成员中,下面是这7种文件类型的判断方法: |
当然这些文件都是有访问权限的,很巧这些权限也是在一个叫struct stat这个结构体中
结构体struct stat中的成员st_mode值包含了对文件的访问权限位,任何类型的文件都有访问权限(access permission)。每个文件有9个访问权限,可以它们分为3类,u表示用户(所有者)、g表示组、o表示其他 st_mode屏蔽 含义 |
那么问题来了既然有权限,我们怎么知道这些权限呢?当然这不是难事,一个access函数就可以解决问题了
函数描述:按实际用户ID和实际组ID进行访问权限测试 |
这是access函数的具体用法的代码(argv[1]必须是一个已经存在的文件):
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main(int argc,char **argv) { if(argc != 2) { printf("argc must equal to two!\n"); exit(1); } if(access(argv[1],F_OK)) //判断文件是否存在 { printf("%s not existence!\n",argv[1]); exit(1); } if(access(argv[1],R_OK)) //判断文件是否可读 { printf("%s not read permission\n",argv[1]); } else { printf("%s have read permission\n",argv[1]); } if(access(argv[1],W_OK)) //判断文件是否可写 { printf("%s not write permission\n",argv[1]); } else { printf("%s have write permission\n",argv[1]); } if(access(argv[1],X_OK)) //判断文件是否可执行 { printf("%s not execute permission\n",argv[1]); } else { printf("%s have execute permission\n",argv[1]); } return 0; }
在ubuntu下运行:
当然了既然有权限,那么我们在创建文件的时候文件权限也是可以自己控制的,umask函数用上场了
|
代码的具体用法如下:
#include <sys/stat.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #define RRR (S_IRUSR|S_IRGRP|S_IROTH) //设置文件权限为用户读、组读、其他读 int main(int argc,char *argv[]) { umask(0); //不设置文件屏蔽字 creat("text",RRR); //以用户读、组读、其他读的权限创建文件text.txt //这里也可以用open umask(S_IRUSR|S_IRGRP); //创建用户读、组出屏蔽字 creat("text1",RRR); //最后创建出来的文件只有其他读的权限 return 0; }
既然文件可以创建,当然目录也是可以创建的,mkdir函数就是为创建目录而生的:
函数描述:创建一个空目录,.和..自动创建 S_IRWXU 用户(所有者)、读、写和执行 S_IRWXO 其他读、写和执行 |
创建目录的具体实现:
#include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> int main(int argc,char *argv[]) { if(mkdir("test.txt",S_IWOTH|S_IRUSR|S_IRGRP) == -1) /*以其他写、用户读、组读权限创建一个空目录*/ { perror("mkdir"); exit(1); } return 0; }
umask函数是在创建文时设置权限,那么在文件被创建之后还能修改权限吗?这时候chmod函数就派上用处了
(1)头文件 #include <sys/stat.h> (2)函数原型 int chmod(const char *path, mode_t mode); (3)参数: a、path:文件路径 b、mode:跟上面midir函数中的成员mode一样,其中的宏位或就可以了
|
改变文件权限的例子:
chmod("text",S_IRUSR|S_IRGRP|S_IROTH); //把text文件的权限改为用户读、组读、其他读
既然权限可以改变权限,当然改个名字也是没问题的,用rename函数轻松解决问题:
(1)头文件 #include <stdio.h> (2)函数原型 int rename(const char *old, const char *new); (3)参数: a、old:文件原来的名字 b、new:新的名字 (4)返回值: 成功:0 失败:-1 |
改变文件名字的例子:
rename("text","hhtext"); //将名字为text的文件改为hhtext
其实文件中还有个小操作就是可以在任何位置截断文件中的内容:
truncate("test",3); //将文件test长度截断为3字节
好了讲了那么多关于文件的权限的东西,是时候讲讲怎么打开一个目录和读目录中的的东西了:
读目录中,要经过三步:打开目录、读目录、关闭目录,对应用到的函数分别为opendir、readdir、closedir。 一、打开目录 (1)头文件 #include <sys/types.h> #include <dirent.h> (2)函数原型 DIR *opendir(const char *name); (3)参数 name:目录名 (4)返回值: 成功:返回一个DIR*型的目录流 失败:NULL 二、读目录 (1)头文件 #include <dirent.h> (2)函数原型 struct dirent *readdir(DIR *dirp); (3)参数 a、dirp:调用opendir函数后返回的DIR*类型的目录流 (4)返回值: 成功:返回一个(struct dirent)型的结构体 下面是struct dirent结构体的具体内容 struct dirent { ino_t d_ino; 节点号 /*inode number */ off_t d_off; 偏移到下一个方向 /* offset to the next dirent */ unsigned short d_reclen; 记录长度 /* length of this record */ unsigned char d_type; 文件类型,不支持所有文件系统类型/* type of file; not supportedby all file system types */ char d_name[256]; 文件名 /* filename */ }; struct dirent中的成员d_type又有以下几种类型: DT_BLK 块设备 (This is a block device.) DT_CHR 字符设备(This is a character device.) DT_DIR 目录( This is a directory.) DT_FIFO 命名管道或FIFO(This is a named pipe (FIFO).) DT_LNK 符号连接(This is a symbolic link.) DT_REG 普通文件(This is a regular file.) DT_SOCK UNIX域套接字( This is a UNIX domain socket.) DT_UNKNOWN 未知类型(The file type is unknown.) 读完或者失败都返回NULL 三、关闭目录 (1)头文件 #include <sys/types.h> #include <dirent.h> (2)函数原型 int closedir(DIR *dirp); (3)参数 a、dirp:用opendir函数后返回的DIR*类型的目录流 (4)返回值: 成功:0 失败:-1 四、更改当前工作路径 (1)头文件 #include <unistd.h> (2)函数原型 int chdir(const char *path); (3)参数: a、path:需要更改的路径 (4)返回值 成功:0 失败:-1 例子: chdir("/test.txt"); //当前工作目录更改到test.txt中 五、获得当前工作目录完整的绝对路径 (1)头文件 #include <unistd.h> (2)函数原型 char *getcwd(char *buf, size_t size); (3)参数: a、buf:存放绝对路径的缓冲区 b、size: 缓冲区的大小 (4)返回值: 成功:返回当前工作目录完整的绝对路径 失败:NULL 例子: char buf[100]; bzero(buf,sizeof(buf)); if(getcwd(buf,sizeof(buf)) == NULL) { perror("getcwd"); exit(1); }
打开一个目录然后读目录中的文件并把文件名打印出来,具体代码如下:
#include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <stdlib.h> #include <stdlib.h> #include <string.h> #include <unistd.h> void open_file(char *name) { DIR * entry; //opendir返回值 struct dirent *ep; //readdir返回值 char path_name[100]; if((entry = opendir(name)) == NULL) { perror("opendir"); exit(1); } while(1) { if((ep = readdir(entry)) == NULL) { break; } if(ep->d_name[0] == '.') //去掉隐藏文件 { continue; } sprintf(path_name,"%s/%s",name,ep->d_name); //拼接两个字符 printf("%s\n",path_name); //输出路径 if(ep->d_type & DT_DIR) //目录 也可以用lstat/stat函数 { open_file(path_name); //递归打开下一目录 } } closedir(entry); } int main(int argc,char *argv[]) { if(argc != 2) { printf("argv[1] have to a directory!\n"); exit(1); } open_file(argv[1]); return 0; }
运行程序的效果图如下:
最后来点小知识:
**每个文件系统所在的设备都有主、次设备号表示 |
具体代码如下:
#include <sys/stat.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> int main(int argc,char *argv[]) { int i; struct stat buf; for(i=1;i<argc;i++) { printf("%s:",argv[i]); if(stat(argv[i],&buf) == -1){ perror("stat"); exit(1); } printf("dev = %d/%d",major(buf.st_dev),minor(buf.st_dev)); //判断是否是字特殊文件(S_ISCHR)块特殊文件(S_ISCHR) if(S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)){ printf(" (%s) rdev = %d/%d", (S_ISCHR(buf.st_mode)) ? "character" : "block", major(buf.st_rdev),minor(buf.st_rdev)); } printf("\n"); } return 0; }
运行结果: