UNIX环境高级编程——文件和目录
一、获取文件/目录的属性信息
int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct stat *buf);
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ 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; /* blocksize for file system I/O */ blkcnt_t st_blocks; /* number of 512B 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 */ };示例程序:
#include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) #define MAJOR(a) (int)((unsigned short)a >> 8) // 高8位,主设备号 #define MINOR(a) (int)((unsigned short)a & 0xFF) int filetype(struct stat *buf) { int flag = 0; printf("Filetype:"); mode_t mode; mode = buf->st_mode; switch (mode & S_IFMT) { case S_IFSOCK: printf("socket\n"); break; case S_IFLNK: printf("symbolic link\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFBLK: printf("block device\n"); flag = 1; break; case S_IFDIR: printf("directory\n"); break; case S_IFCHR: printf("character device\n"); flag = 1; break; case S_IFIFO: printf("FIFO\n"); break; default: printf("unknown file type\n"); break; } return flag; } void fileperm(struct stat *buf, char perm[]) { strcpy(perm, "----------"); perm[0] = '?'; mode_t mode; mode = buf->st_mode; switch (mode & S_IFMT) { case S_IFSOCK: perm[0] = 's'; break; case S_IFLNK: perm[0] = 'l'; break; case S_IFREG: perm[0] = '-'; break; case S_IFBLK: perm[0] = 'b'; break; case S_IFDIR: perm[0] = 'd'; break; case S_IFCHR: perm[0] = 'c'; break; case S_IFIFO: perm[0] = 'p'; break; } if (mode & S_IRUSR) perm[1] = 'r'; if (mode & S_IWUSR) perm[2] = 'w'; if (mode & S_IXUSR) perm[3] = 'x'; if (mode & S_IRGRP) perm[4] = 'r'; if (mode & S_IWGRP) perm[5] = 'w'; if (mode & S_IXGRP) perm[6] = 'x'; if (mode & S_IROTH) perm[7] = 'r'; if (mode & S_IWOTH) perm[8] = 'w'; if (mode & S_IXOTH) perm[9] = 'x'; perm[10] = '\0'; } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage %s file\n", argv[0]); exit(EXIT_FAILURE); } printf("Filename:%s\n", argv[1]); struct stat sbuf; if (lstat(argv[1], &sbuf) == -1) ERR_EXIT("stat error"); printf("file in Dev number:major %d, minor %d\n", MAJOR(sbuf.st_dev), MINOR(sbuf.st_dev)); printf("File inode:%d\n", (int) sbuf.st_ino); if (filetype(&sbuf)) { printf("Device number:major %d, minor %d\n", MAJOR(sbuf.st_rdev), MINOR(sbuf.st_rdev)); } char perm[11] = {0}; fileperm(&sbuf, perm); printf("File permission bits=%o %s\n", sbuf.st_mode & 07777, perm); return 0; }测试如下:
huangcheng@ubuntu:~$ ./a.out hc Filename:hc file in Dev number:major 8, minor 1 File inode:929485 Filetype:regular file File permission bits=644 -rw-r--r--
二、目录的访问
功能说明:打开一个目录
原型:DIR* opendir(char *pathname);
返回值:
打开成功,返回一个目录指针
打开失败,则返回NULL
功能说明:访问指定目录中下一个连接的细节
原型:struct dirent* readdir(DIR *dirptr);
返回值:
返回一个指向dirent结构的指针,它包含指定目录中下一个连接的细节;
没有更多连接时,返回NULL
功能说明:关闭一个已经打开的目录
原型:int closedir (DIR *dirptr);
返回值:调用成功返回0,失败返回-1
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 supported by all file system types */ char d_name[256]; /* filename */ };
三、目录的创建删除和权限设置
功能说明:用来创建一个称为pathname的新目录,它的权限位设置为mode
原型:int mkdir(char *pathname,mode_t mode);
返回值:调用成功返回0,失败返回-1
功能说明:删除一个空目录
原型:int rmdir(char *pathname);
返回值:调用成功返回0,失败返回-1
功能说明:用来改变给定路径名pathname的文件的权限位。为了改变一个文件的权限位,进程的有效用户ID必须等于文件的所有者ID,或者该进程必须具有超级用户的权限。
原型:int chmod (char *pathname, mode_t mode);
int fchmod (int fd, mode_t mode);
返回值:调用成功返回0,失败返回-1
功能说明:用来改变文件所有者的识别号(owner id)或者它的用户组识别号(group ID),如若两个参数owner或group中的任意一个为-1,则对应的ID不变。
原型:int chown (char *pathname, uid_t owner,gid_t group);
int fchown (int fd, uid_t owner,gid_t group);
返回值:调用成功返回0,失败返回-1
示例代码:
#include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<dirent.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { DIR *dir = opendir("."); struct dirent *de; while ((de = readdir(dir)) != NULL) { if (strncmp(de->d_name, ".", 1) == 0) continue; //忽略隐藏文件 printf("%s\n", de->d_name); } closedir(dir); exit(EXIT_SUCCESS); // 等价于return 0 }
四、文件长度
stat结构成员st_size表示以字节为单位的文件长度。此字段只对普通文件、目录文件盒符号链接有意义。
对于普通文件,其文件长度可以是0,在读这种文件时,将得到文件结束指示。
对于目录,文件长度通常是一个数(例如512)的倍数。
对于符号链接,文件长度是文件名中的实际字节数(即huangcheng的符号链接为10,不包括c语言用作名字结尾的null字符)
五、文件截短
int truncate(const char *path, off_t length); int ftruncate(int fd, off_t length);这两个函数将把现有的文件长度截短length字节。如果该文件以前的长度大于length,则超过length以外的数据就被删除。
六、chdir、fchdir和getcwd函数
每个进程都有一个当前目录,此目录是搜索所有相对路径名的起点。当前工作目录是进程的一个属性,起始目录则是登陆名(/etc/passwd)的一个属性。
int chdir(const char *path); int fchdir(int fd);
这两个函数中,分别用path或打开文件描述符指定新的当前工作目录。
char *getcwd(char *buf, size_t size);
把当前目录的绝对地址保存到 buf 中,buf 的大小为 size。如果 size太小无法保存该地址,返回 NULL 并设置 errno 为 ERANGE。可以采取令 buf 为 NULL并使 size 为负值来使 getcwd 调用 malloc 动态给 buf 分配,但是这种情况要特别注意使用后释放缓冲以防止内存泄漏。