2. 文件和目录
2.1 文件
2.1.1 获取文件状态stat()
帮助手册:
man 2 stat
包含头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
函数原型:
int stat(const char *pathname, struct stat *statbuf);
参数 | 说明 |
---|---|
pathname | 文件名 |
statbuf | 文件状态结构体 |
return | 成功:0 失败:-1,设置errno |
文件状态结构体
struct stat {
dev_t st_dev; /* 文件的设备编号 */
ino_t st_ino; /* 索引节点号 */
mode_t st_mode; /* 文件类型和权限 */
nlink_t st_nlink; /* 硬连接数 */
uid_t st_uid; /* 所有者用户ID */
gid_t st_gid; /* 所有者组ID */
dev_t st_rdev; /* 设备ID(特殊文件) */
off_t st_size; /* 大小(字节) */
blksize_t st_blksize; /* 文件系统的I/O缓冲区大小 */
blkcnt_t st_blocks; /* 分配的512B块数 */
struct timespec st_atim; /* 最近访问 */
struct timespec st_mtim; /* 最近更改 */
struct timespec st_ctim; /* 最近改动 */
#define st_atime st_atim.tv_sec /* 向后兼容性 */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
struct timespec {
__kernel_time_t tv_sec; /* 秒 */
long tv_nsec; /* 纳秒 */
st_mode 定义了下列数种情况::
宏 | 值 | 说明 |
---|---|---|
S_IFMT | 0170000 | 文件类型的位遮罩 |
S_IFSOCK | 0140000 | scoket |
S_IFLNK | 0120000 | 符号连接 |
S_IFREG | 0100000 | 一般文件 |
S_IFBLK | 0060000 | 区块装置 |
S_IFDIR | 0040000 | 目录 |
S_IFCHR | 0020000 | 字符装置 |
S_IFIFO | 0010000 | 先进先出 |
S_ISUID | 04000 | 文件的(set user-id on execution)位 |
S_ISGID | 02000 | 文件的(set group-id on execution)位 |
S_ISVTX | 01000 | 文件的sticky位 |
S_IRUSR | 00400 | 文件所有者具可读取权限 |
S_IWUSR | 00200 | 文件所有者具可写入权限 |
S_IXUSR | 00100 | 文件所有者具可执行权限 |
S_RWXU | 00700 | 文件所有者具有读,写和执行权限 |
S_IRGRP | 00040 | 用户组具可读取权限 |
S_IWGRP | 00020 | 用户组具可写入权限 |
S_IXGRP | 00010 | 用户组具可执行权限 |
S_IROTH | 00004 | 其他用户具可读取权限 |
S_IWOTH | 00002 | 其他用户具可写入权限 |
S_IXOTH | 00001 | 其他用户具可执行权限 |
上述的文件类型在POSIX中定义了检查这些类型的宏定义:
宏 | 说明 |
---|---|
S_ISLNK (st_mode) | 判断是否为符号连接 |
S_ISREG (st_mode) | 是否为一般文件 |
S_ISDIR (st_mode) | 是否为目录 |
S_ISCHR (st_mode) | 是否为字符装置文件 |
S_ISBLK (st_mode) | 是否为块设备 |
S_ISSOCK (st_mode) | 是否为socket |
2.1.1.1 通过uid获取用户名getpwuid()
struct passwd *getpwuid(uid_t uid);
包含头文件:
#include <sys/types.h>
#include <pwd.h>
struct passwd {
char *pw_name; /* 用户名 */
char *pw_passwd /* 用户密码 */
char *pw_gecos; /* 用户信息 */
char *pw_dir; /* 家目录 */
char *pw_sheel; /* shell程序 */
uid_t pw_uid; /* 用户ID */
gid_t pw_gid; /* 组ID */
};
2.1.1.2 通过gid获取组名getgrgid
struct group *getgrgid(gid_t gid);
包含头文件:
#include <sys/tyeps.h>
#include <grp.h>
struct group {
char *gr_name; /* 组名 */
char *gr_passwd; /* 组密码 */
char **gr_mem; /* 指向组成员名称的以NULL结尾的指针数组 */
git_t gr_gid; /* 组ID */
};
2.1.1.3 通过秒数获取本地时间localtime
struct tm *localtime(const time_t *timep);
struct tm {
int tm_sec; /* 秒(0-60) */
int tm_min; /* 分(0-59) */
int tm_hour; /* 时(O-23) */
int tm_mday; /* 天(1-31) */
int tm_mon; /* 月(0-11) */
int tm_year; /* 年-1900 */
int tm_wday; /* 星期(0-6,Sun=0) */
int tm_yday; /* 一年中第几天(0-365,1 Jan = 0) */
int tm_isdst; /* 夏令时间 */
};
查看文件信息示例代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
int main(int argc, char* argv[])
{
struct stat sb;
stat(argv[1], &sb);
char stmode[11] = { 0 };
// 解析st_mode
memset(stmode, '-', sizeof(stmode)-1);
if(S_ISDIR(sb.st_mode)) stmode[0] = 'd';
if(S_ISCHR(sb.st_mode)) stmode[0] = 'c';
if(S_ISBLK(sb.st_mode)) stmode[0] = 'b';
if(S_ISFIFO(sb.st_mode)) stmode[0] = 'p';
if(S_ISLNK(sb.st_mode)) stmode[0] = 'l';
if(S_ISSOCK(sb.st_mode)) stmode[0] = 's';
if(sb.st_mode & S_IRUSR) stmode[1] = 'r';
if(sb.st_mode & S_IWUSR) stmode[2] = 'w';
if(sb.st_mode & S_IXUSR) stmode[3] = 'x';
if(sb.st_mode & S_IRGRP) stmode[4] = 'r';
if(sb.st_mode & S_IWGRP) stmode[5] = 'w';
if(sb.st_mode & S_IXGRP) stmode[6] = 'x';
if(sb.st_mode & S_IROTH) stmode[7] = 'r';
if(sb.st_mode & S_IWOTH) stmode[8] = 'w';
if(sb.st_mode & S_IXOTH) stmode[9] = 'x';
struct tm *filetm = localtime(&sb.st_atim.tv_sec);
char timebuf[20] = { 0 };
sprintf(timebuf, "%d月 %d %02d:%02d", filetm->tm_mon+1,filetm->tm_mday, filetm->tm_hour, filetm->tm_min);
printf("%s %ld %s %s %ld %s %s\n",stmode, sb.st_nlink, getpwuid(sb.st_uid)->pw_name, getgrgid(sb.st_gid)->gr_name, sb.st_size, timebuf, argv[1]);
return 0;
}
lstata()和stat()的区别:
stat()有穿透效果,当遇到软连接会通过软连接找到硬连接
lstat()没有穿透效果
2.1.2 判断有效用户对一个文件的权限或文件是否存在access()
帮助手册:
man 2 access
包含头文件:
#include <unistd.h>
函数原型:
int access(const char *pathname, int mode);
参数 | 说明 |
---|---|
pathname | 文件路径 |
mode | R_OK:读 W_OK:写 X_OK:执行 F_OK:存在 |
return | 成功:0 失败:-1 |
示例:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
if(access(argv[1], R_OK) == 0) printf("%s read ok!\n", argv[1]);
if(access(argv[1], W_OK) == 0) printf("%s write ok!\n", argv[1]);
if(access(argv[1], X_OK) == 0) printf("%s execute ok!\n", argv[1]);
if(access(argv[1], F_OK) == 0) printf("%s existence!\n", argv[1]);
return 0;
}
2.1.3 修改文件权限chmod()
帮助手册:
man 2 chmod
包含头文件:
#include <sys/stat.h>
函数原型:
int chmod(const char *pathname, mode_t mode);
参数 | 说明 |
---|---|
pathname | 文件路径 |
mode | 新的权限 |
return | 成功:0 失败:-1,并设置errno |
2.1.4 改变文件所有权chown()
帮助手册:
man 2 chown
包含头文件:
#include <unistd.h>
函数原型:
int chown(const char *pathname, uid_t owner, gid_t group);f
参数 | 说明 |
---|---|
pathname | 文件路径 |
owenr | 用户ID(/etc/passwd) |
group | 组ID(/etc/group) |
return | 成功:0 失败:-1,并设置errno |
2.1.5 截断一个文件到一个指定长度truncate()
帮助手册:
man 2 truncate
包含头文件:
#include <unistd.h>
#include <sys/types.h>
函数原型
int truncate(const char *path, off_t length);
参数 | 说明 |
---|---|
path | 文件路径 |
length | 截断长度 |
return | 成功:0 失败:-1,并设置errno |
示例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
truncate(argv[1], 1024);
return 0;
}
2.1.6 创建硬连接link()
帮助手册:
man 2 link
包含头文件:
#include <unistd.h>
函数原型:
int link(const char *oldpath, const char *newpath);
参数 | 说明 |
---|---|
oldpath | 原路径 |
newpath | 新路径 |
return | 成功:0 失败:-1,并设置errno |
示例:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
link(argv[1], argv[2]);
return 0;
}
2.1.7 创建软连接symlink()
帮助手册:
man 2 symlink
包含头文件:
#include <unistd.h>
函数原型:
int symlink(const char *target, const char *linkpath);
参数 | 说明 |
---|---|
target | 原目标 |
linkpath | 软连接路径 |
return | 成功:0 失败:-1,并设置errno |
示例:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
symlink(argv[1], argv[2]);
return 0;
}
2.1.8 读一个软连接readlink()
帮助手册:
man 2 readlink
包含头文件:
-#include <unistd.h>
函数原型:
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
参数 | 说明 |
---|---|
pathname | 软连接路径 |
buf | 缓冲区 |
bufsiz | 缓冲区大小 |
return | 成功:大小 失败:-1,设置errno |
示例:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
char buf[32] = { 0 };
readlink(argv[1], buf, sizeof(buf));
printf("buf is %s\n", buf); # argv[1]
return 0;
}
2.1.9 删除一个连接unlink()
帮助手册:
man 2 unlink
包含头文件:
#include <unistd.h>
函数原型:
int unlink(const char *pathname);
参数 | 说明 |
---|---|
pathname | 路径 |
return | 成功:0 失败:-1,并设置errno |
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
unlink(argv[1]);
return 0;
}
注:当文件被打开,但是所有硬连接被unlink,当打开这个文件的进程结束后,这个文件才会被删除。
2.1.10 更改一个文件或目录的名字或位置rename()
帮助手册:
man 2 rename
包含头文件:
#include <stdio.h>
函数原型:
int rename(const char *oldpath, const char *newpath);
参数 | 说明 |
---|---|
oldpath | 原路径 |
newpath | 新路径 |
return | 成功:0 失败:-1,并设置errno |
示例:
#include <stdio.h>
int main(int argc, char* argv[])
{
rename(argv[1], argv[2]);
return 0;
}
2.2 目录
2.2.1 获取当前工作路径getcwd()
帮助手册:
man 2 getcwd
包含头文件:
#include <unistd.h>
函数原型:
char *getcwd(char *buf, size_t size);
参数 | 说明 |
---|---|
buf | 传出缓冲区 |
size | 缓冲区大小 |
return | 成功:当前工作路径的指针 失败:NULL,并设置errno |
2.2.2 改变工作目录chdir()
帮助手册:
man 2 getcwd
包含头文件:
#include <unistd.h>
函数原型:
char *chdir(char *path);
参数 | 说明 |
---|---|
path | 新路径 |
return | 成功:0 失败:-1,并设置errno |
2.2.3 创建目录mkdir()
帮助手册:
man 2 mkdir
包含头文件:
#include <sys/stat.h>
#include <sys/types.h>
函数原型:
int mkdir(const char *pathname, mode_t mode);
参数 | 说明 |
---|---|
pathname | 目录名 |
mode | 目录权限 |
return | 成功:0 失败:-1,并设置errno |
示例:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
char buf[256] = { 0 };
chdir("../");
getcwd(buf, sizeof(buf));
printf("current working path: %s\n", buf);
mkdir("newdir", 0777);
return 0;
}
2.2.4 删除空目录rmdir()
帮助手册:
man 2 rmdir
包含头文件:
#include <unistd.h>
函数原型:
int rmdir(const char *pathname);
参数 | 说明 |
---|---|
pathname | 目录路径 |
return | 成功:0 失败:-1并设置errno |
2.2.5 打开目录opendir()
帮助手册:man opendir`
包含头文件:
#include <sys/types.h>
#include <dirent.h>
函数原型:
int rmdir(const char *pathname);
参数 | 说明 |
---|---|
pathname | 目录路径 |
return | 成功:目录流的指针 失败:NULL,并设置errno |
2.2.4 读目录readdir()
帮助手册:
man 3 readdir
包含头文件:
#include <dirent.h>
函数原型:
struct dirent *readdir(DIR *dirp);
参数 | 说明 |
---|---|
dirp | 目录流的指针 |
return | 成功:下一个目录进入点 失败:NULL,并设置errno 读到目录文件尾:NULL |
struct dirent {
ino_t d_ino; /* Inode号 */
off_t d_off; /* 目录文件开头至此目录进入点的位移 */
unsigned short d_reclen; /* d_name的长度 */
unsigned char d_type; /* d_name所指的文件类型 */
char d_name[256]; /* 文件名 */
};
d_type值说明:
值 | 说明 |
---|---|
DT_BLK | 块设备 |
DT_CHR | 字符设备 |
DT_DIR | 目录 |
DT_FIFO | 管道 |
DT_LNK | 软连接 |
DT_REG | 普通文件 |
DT_SOCK | sock |
DT_UNKNOWN | 未知类型 |
2.2.5 关闭目录closedir()
帮助手册:
man 3 closedir
包含头文件:
#include <sys/types.h>
#include <dirent.h>
函数原型:
int closedir(DIR *dirp);
参数 | 说明 |
---|---|
dirp | 目录流的指针 |
return | 成功:0 失败:-1,并设置errno |
示例:
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>
int count = 0;
int DirCount(char *dirname)
{
DIR *dirp = opendir(dirname);
if(dirp == NULL)
return -1;
struct dirent *dentp = NULL;
while((dentp = readdir(dirp)) != NULL)
{
if(dentp->d_type == DT_DIR)
{
if(strcmp(".", dentp->d_name) == 0 || strcmp("..", dentp->d_name) == 0)
continue;
char newdirname[1024] = { 0 };
sprintf(newdirname, "%s/%s", dirname, dentp->d_name);
DirCount(newdirname);
}
printf("%s/%s\n", dirname, dentp->d_name);
count++;
}
closedir(dirp);
return 0;
}
int main(int argc, char* argv[])
{
DirCount(argv[1]);
printf("count = %d\n", count);
return 0;
}
2.2.6 重设读取目录的位置为开头位置rewinddir()
帮助手册:
man 3 rewinddir
包含头文件:
#include <sys/types.h>
#include <dirent.h>
函数原型:
void rewinddir(DIR *dirp);
参数 | 说明 |
---|---|
dirp | 目录流的指针 |
return | void |
2.2.7 获取目录流的读取位置telldir()
帮助手册:
man 3 telldir
包含头文件:
#include <sys/types.h>
#include <dirent.h>
函数原型:
long telldir(DIR *dirp);
参数 | 说明 |
---|---|
dirp | 目录流的指针 |
return | 成功:下一个读取位置 失败:-1,并设置errno |
2.2.8 设置下次读取目录的位置seekdir()
帮助手册:
man 3 seekdir
包含头文件:
#include <dirent.h>
函数原型:
void seekdir(DIR *dirp, long loc);
参数 | 说明 |
---|---|
dirp | 目录流的指针 |
loc | 距离目录文件开头的偏移量 |
return | void |
2.3 错误信息errno
包含头文件:
/usr/include/asm-generic/errno-base.h
/usr/include/asm-generic/errno.h
/usr/include/errno.h
etc
查找
errno
头文件
sudo find /usr/ -name "errno*.h"