1 文件属性操作函数
- 判断文件是否存在及权限
int access(const char *pathname, int mode);
access.c
/*
#include <unistd.h>
int access(const char *pathname, int mode);
作用:判断某个文件是否有某个权限,或者判断文件是否存在
参数:
- pathname: 判断的文件路径
- mode:
R_OK: 判断是否有读权限
W_OK: 判断是否有写权限
X_OK: 判断是否有执行权限
F_OK: 判断文件是否存在
返回值:成功返回0, 失败返回-1
*/
#include <unistd.h>
#include <stdio.h>
int main() {
int ret = access("a.txt", F_OK);
if(ret == -1) {
perror("access");
return -1;
}
printf("文件存在!\n");
return 0;
}
运行示例代码。
root@LDY:~/cpp-study/lesson13# gcc access.c -o access
root@LDY:~/cpp-study/lesson13# ./access
文件存在!
- 修改文件权限
int chmod(const char *filename, int mode);
chmod.c
/*
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
修改文件的权限
参数:
- pathname: 需要修改的文件的路径
- mode:需要修改的权限值,八进制的数
返回值:成功返回0,失败返回-1
*/
#include <sys/stat.h>
#include <stdio.h>
int main() {
int ret = chmod("a.txt", 0777);
if(ret == -1) {
perror("chmod");
return -1;
}
return 0;
}
运行示例代码,修改 a.txt 。
root@LDY:~/cpp-study/lesson13# ll a.txt
-rw-r--r-- 1 root root 0 Oct 26 19:36 a.txt
root@LDY:~/cpp-study/lesson13# gcc chmod.c -o chmod
root@LDY:~/cpp-study/lesson13# ./chmod
root@LDY:~/cpp-study/lesson13# ll a.txt
-rwxrwxrwx 1 root root 0 Oct 26 19:36 a.txt*
-
修改文件所有者和所在组
int chown(const char *path, uid_t owner, gid_t group);
用户id在/etc/passwd
组id在/etc/group
-
改变文件大小
int truncate(const char *path, off_t length);
truncate.c
/*
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
作用:缩减或者扩展文件的尺寸至指定的大小
参数:
- path: 需要修改的文件的路径
- length: 需要最终文件变成的大小
返回值:
成功返回0, 失败返回-1
*/
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main() {
int ret = truncate("b.txt", 5);
if(ret == -1) {
perror("truncate");
return -1;
}
return 0;
}
运行示例代码。
root@LDY:~/cpp-study/lesson13# ll b.txt
-rw-r--r-- 1 root root 11 Oct 26 19:54 b.txt
root@LDY:~/cpp-study/lesson13# gcc truncate.c -o truncate
root@LDY:~/cpp-study/lesson13# ./truncate
root@LDY:~/cpp-study/lesson13# ll b.txt
-rw-r--r-- 1 root root 5 Oct 26 19:57 b.txt
2 目录操作函数
- 创建目录
int mkdir(const char *pathname, mode_t mode);
最终权限需要和umask相与,拥有可执行权限才能进入目录
mkdir.c
/*
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
作用:创建一个目录
参数:
pathname: 创建的目录的路径
mode: 权限,八进制的数
返回值:
成功返回0, 失败返回-1
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
int main() {
int ret = mkdir("aaa", 0777);
if(ret == -1) {
perror("mkdir");
return -1;
}
return 0;
}
运行示例代码。
root@LDY:~/cpp-study/lesson14# gcc mkdir.c -o mkdir
root@LDY:~/cpp-study/lesson14# ./mkdir
root@LDY:~/cpp-study/lesson14# ls
aaa mkdir mkdir.c
root@LDY:~/cpp-study/lesson14#
- 删除空目录
int rmdir(const char *pathname);
- 重命名目录
int rename(const char *oldpath, const char *newpath);
rename.c
/*
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
作用:重命名目录
参数:
oldpath: 原路径
newpath: 新路径
返回值:
成功返回0, 失败返回-1
*/
#include <stdio.h>
int main() {
int ret = rename("aaa", "bbb");
if(ret == -1) {
perror("rename");
return -1;
}
return 0;
}
运行示例代码。
root@LDY:~/cpp-study/lesson14# gcc rename.c -o rename
root@LDY:~/cpp-study/lesson14# ./rename
root@LDY:~/cpp-study/lesson14# ls
bbb mkdir mkdir.c rename rename.c
- 更改当前工作目录
int chdir(const char *path);
- 获取当前工作目录
char *getcwd(char *buf, size_t size);
chdir.c
/*
#include <unistd.h>
int chdir(const char *path);
作用:修改进程的工作目录
比如在/home/nowcoder 启动了一个可执行程序a.out, 进程的工作目录 /home/nowcoder
参数:
path : 需要修改的工作目录
返回值:
成功返回0, 失败返回-1
#include <unistd.h>
char *getcwd(char *buf, size_t size);
作用:获取当前工作目录
参数:
- buf : 存储的路径,指向的是一个数组(传出参数)
- size: 数组的大小
返回值:
返回的指向的一块内存,这个数据就是第一个参数
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main() {
// 获取当前的工作目录
char buf[128];
getcwd(buf, sizeof(buf));
printf("当前的工作目录是:%s\n", buf);
// 修改工作目录
int ret = chdir("/root/cpp-study/lesson14/bbb");
if(ret == -1) {
perror("chdir");
return -1;
}
// 创建一个新的文件
int fd = open("chdir.txt", O_CREAT | O_RDWR, 0664);
if(fd == -1) {
perror("open");
return -1;
}
close(fd);
// 获取当前的工作目录
char buf1[128];
getcwd(buf1, sizeof(buf1));
printf("当前的工作目录是:%s\n", buf1);
return 0;
}
运行示例代码。
root@LDY:~/cpp-study/lesson14# gcc chdir.c -o chdir
root@LDY:~/cpp-study/lesson14# ./chdir
当前的工作目录是:/root/cpp-study/lesson14
当前的工作目录是:/root/cpp-study/lesson14/bbb
root@LDY:~/cpp-study/lesson14# tree
.
├── bbb
│ └── chdir.txt
├── chdir
├── chdir.c
├── mkdir
├── mkdir.c
├── rename
└── rename.c
1 directory, 7 files
3 目录遍历函数
- 打开目录
DIR *opendir(const char *name);
- 读取目录
struct dirent *readdir(DIR *dirp);
- 关闭目录
int closedir(DIR *dirp);
- dirent 结构体
struct dirent { ino_t d_ino; // 此目录进入点的inode off_t d_off; // 目录文件开头至此目录进入点的位移 unsigned short int d_reclen; // d_name 的长度, 不包含NULL字符 unsigned char d_type; // d_name 所指的文件类型 char d_name[256]; // 文件名 };
- d_type
- DT_BLK - 块设备
- DT_CHR - 字符设备
- DT_DIR - 目录
- DT_LNK - 软连接
- DT_FIFO - 管道
- DT_REG - 普通文件
- DT_SOCK - 套接字
- DT_UNKNOWN - 未知
readFileNum.c
统计文件中普通文件个数。
/*
// 打开一个目录
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
参数:
- name: 需要打开的目录的名称
返回值:
DIR * 类型,理解为目录流
错误返回NULL
// 读取目录中的数据
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
- 参数:dirp是opendir返回的结果
- 返回值:
struct dirent,代表读取到的文件的信息
读取到了末尾或者失败了,返回NULL
// 关闭目录
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
*/
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int getFileNum(const char * path);
// 读取某个目录下所有的普通文件的个数
int main(int argc, char * argv[]) {
if(argc < 2) {
printf("%s path\n", argv[0]);
return -1;
}
int num = getFileNum(argv[1]);
printf("普通文件的个数为:%d\n", num);
return 0;
}
// 用于获取目录下所有普通文件的个数
int getFileNum(const char * path) {
// 1.打开目录
DIR * dir = opendir(path);
if(dir == NULL) {
perror("opendir");
exit(0);
}
struct dirent *ptr;
// 记录普通文件的个数
int total = 0;
while((ptr = readdir(dir)) != NULL) {
// 获取名称
char * dname = ptr->d_name;
// 忽略掉. 和..
if(strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {
continue;
}
// 判断是否是普通文件还是目录
if(ptr->d_type == DT_DIR) {
// 目录,需要继续读取这个目录
char newpath[256];
sprintf(newpath, "%s/%s", path, dname);
total += getFileNum(newpath);
}
if(ptr->d_type == DT_REG) {
// 普通文件
total++;
}
}
// 关闭目录
closedir(dir);
return total;
}
运行示例代码。
root@LDY:~/cpp-study/lesson15# gcc readFileNum.c -o rfn
root@LDY:~/cpp-study/lesson15# ./rfn /opt
普通文件的个数为:4872
4 dup、dup2函数
- 复制文件描述符
int dup(int oldfd);
指向同一个文件
dup.c
/*
#include <unistd.h>
int dup(int oldfd);
作用:复制一个新的文件描述符
fd=3, int fd1 = dup(fd),
fd指向的是a.txt, fd1也是指向a.txt
从空闲的文件描述符表中找一个最小的,作为新的拷贝的文件描述符
*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main() {
int fd = open("a.txt", O_RDWR | O_CREAT, 0664);
int fd1 = dup(fd);
if(fd1 == -1) {
perror("dup");
return -1;
}
printf("fd : %d , fd1 : %d\n", fd, fd1);
close(fd);
char * str = "hello,world\n";
int ret = write(fd1, str, strlen(str));
if(ret == -1) {
perror("write");
return -1;
}
close(fd1);
return 0;
}
运行示例代码,用复制得到的文件描述符向原文件描述符指向的文件写数据。
root@LDY:~/cpp-study/lesson16# gcc dup.c -o dup
root@LDY:~/cpp-study/lesson16# ./dup
fd : 3 , fd1 : 4
root@LDY:~/cpp-study/lesson16# cat a.txt
hello,world
- 重定向文件描述符
int dup2(int oldfd, int newfd);
dup2.c
/*
#include <unistd.h>
int dup2(int oldfd, int newfd);
作用:重定向文件描述符
oldfd 指向 a.txt, newfd 指向 b.txt
调用函数成功后:newfd 和 b.txt 做close, newfd 指向了 a.txt
oldfd 必须是一个有效的文件描述符
oldfd和newfd值相同,相当于什么都没有做
*/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main() {
int fd = open("1.txt", O_RDWR | O_CREAT, 0664);
if(fd == -1) {
perror("open");
return -1;
}
int fd1 = open("2.txt", O_RDWR | O_CREAT, 0664);
if(fd1 == -1) {
perror("open");
return -1;
}
printf("fd : %d, fd1 : %d\n", fd, fd1);
int fd2 = dup2(fd, fd1);
if(fd2 == -1) {
perror("dup2");
return -1;
}
// 通过fd1去写数据,实际操作的是1.txt,而不是2.txt
char * str = "hello, dup2\n";
int len = write(fd1, str, strlen(str));
if(len == -1) {
perror("write");
return -1;
}
printf("fd : %d, fd1 : %d, fd2 : %d\n", fd, fd1, fd2);
close(fd);
close(fd1);
return 0;
}
运行示例代码。
root@LDY:~/cpp-study/lesson16# gcc dup2.c -o dup2
root@LDY:~/cpp-study/lesson16# ./dup2
fd : 3, fd1 : 4
fd : 3, fd1 : 4, fd2 : 4
root@LDY:~/cpp-study/lesson16# cat 1.txt
hello, dup2
root@LDY:~/cpp-study/lesson16# cat 2.txt
5 fcntl函数
- 复制文件描述符,设置/获取文件的状态标志
int fcntl(int fd, int cmd, ... /* arg */ );
还有其他功能
fcntl.c
/*
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ...);
参数:
fd : 表示需要操作的文件描述符
cmd: 表示对文件描述符进行如何操作
- F_DUPFD : 复制文件描述符,复制的是第一个参数fd,得到一个新的文件描述符(返回值)
int ret = fcntl(fd, F_DUPFD);
- F_GETFL : 获取指定的文件描述符文件状态flag
获取的flag和我们通过open函数传递的flag是一个东西。
- F_SETFL : 设置文件描述符文件状态flag
必选项:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改
可选性:O_APPEND, O_NONBLOCK
O_APPEND 表示追加数据
O_NONBLOK 设置成非阻塞
阻塞和非阻塞:描述的是函数调用的行为。
*/
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main() {
// 1.复制文件描述符
// int fd = open("1.txt", O_RDONLY);
// int ret = fcntl(fd, F_DUPFD);
// 2.修改或者获取文件状态flag
int fd = open("1.txt", O_RDWR);
if(fd == -1) {
perror("open");
return -1;
}
// 获取文件描述符状态flag
int flag = fcntl(fd, F_GETFL);
if(flag == -1) {
perror("fcntl");
return -1;
}
// 不能直接添加新的状态,原来的状态会被替换,
// 要在原有状态的基础上追加
flag |= O_APPEND; // flag = flag | O_APPEND
// 修改文件描述符状态的flag,给flag加入O_APPEND这个标记
int ret = fcntl(fd, F_SETFL, flag);
if(ret == -1) {
perror("fcntl");
return -1;
}
char * str = "你好\n";
write(fd, str, strlen(str));
close(fd);
return 0;
}
运行示例代码,向文件追加内容。
root@LDY:~/cpp-study/lesson17# gcc fcntl.c -o fcntl
root@LDY:~/cpp-study/lesson17# ./fcntl
root@LDY:~/cpp-study/lesson17# cat 1.txt
你好
参考链接
https://www.nowcoder.com/study/live/504/1/30