文件的打开
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 打开一个已经存在的文件
int open(const char *pathname, int flags);
参数:
- pathname:要打开的文件路径
- flags:对文件操作的权限设置还有其他的设置
O_RDONLY, O_WRONLY, O_RDWR // 这三个设置是互斥的
返回值:
- 返回一个新的文件描述符,如果调用失败,返回-1
// errno:属于Linux系统函数库,库里边的全局变量,记录最近的错误号。
// 打印errno对应的错误描述
#include <stdio.h>
void perror(const char *s);
// s参数:用户描述,比如"hello",实际输出的内容是 hello:xxx(实际的错误描述)
// 关闭文件
#include <unistd.h>
int close(int fd);
// 创建一个新的文件
int open(const char *pathname, int flags, mode_t mode);
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
int main(){
int fd = open("./a.txt", O_RDONLY);
std::cout << fd << std::endl;
if (fd == -1) {
perror("open");
}
// 关闭
close(fd);
return 0;
}
文件的创建
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags, mode_t mode);
参数:
- pathname:创建的文件路径
- flags:对文件的操作权限和其他设置
- 必选项 O_RDONLY, O_WRONLY, O_RDWR 互斥
- 可选项 O_CREAT 文件不存在,创建新文件
- mode:八进制的数,表示用户对创建出的新的文件的操作权限,比如0775
最终的权限是:mode & ~umask
umash:0002 -> 二进制0 000 000 010 ~0002 -> 0775 -> 二进制 0 111 111 101
0777 -> 二进制 0 111 111 111
~0002-> 二进制 0 111 111 101
&
0 111 111 101
umask的作用是抹去某些权限,让我们创建的文件或者目录的权限合理
flags参数占4个字节,32位
flags 32位,每一位都是标志位,代表一种情况
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd = open("./creat.txt", O_RDWR | O_CREAT, 0666);
if (fd == -1) {
perror("open");
}
close(fd);
return 0;
}
文件的读写
/*
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
- fd:文件描述符,open得到的,通过文件描述符操作文件
- buf:缓冲区。需要读取数据存放的的地方。
- count:指定的数组的大小
返回值:
- 成功:
>0:返回实际读取到的字节数
=0:文件已经读取完了
- 失败:-1,并且设置errno
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
- fd:文件描述符
- buf:往磁盘写入的数据。数组
- coutn:要写的数据的实际大小
返回值:
- 成功:实际写入的字节数
- 失败:返回-1,并设置errno
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
// 通过open打开english.txt文件
int srcfd = open("./english.txt", O_RDONLY);
if (srcfd == -1) {
perror("open");
return -1;
}
// 创建新的文件
int destfd = open("./english_copy.txt", O_WRONLY | O_CREAT, 0664);
if (destfd == -1) {
perror("open");
return -1;
}
// 频繁的读写操作
char buf[1024] = {0};
int len = 0;
while ((len = read(srcfd, buf, sizeof(buf))) > 0)
{
int l = write(destfd, buf, len);
}
// 关闭文件
close(destfd);
close(srcfd);
return 0;
}
文件偏移量的重新定位
/*
标准C库函数
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
linux系统函数
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:
- offset:偏移量
- whence:
SEEK_SET:设置文件指针的偏移量
SEEK_CUR:设置偏移量,当前位置+第二个参数offset值
SEEK_END:设置偏移量,文件大小+第二个参数offset值
返回值:返回文件指针最终的位置
作用:
1、移动指针到文件开头
lseek(fd, 0, SEEK_SET);
2、获取当前指针的位置
lseek(fd, 0, SEEK_CUR);
3、获取文件长度
lseek(fd, 0, SEEK_END);
4、拓展文件长度,当前文件10b,拓展到110b
lseek(fd, 100, SEEK_END);
// 需要写入一次数据
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(){
int fd = open("./hello.txt", O_RDWR);
if (fd == -1) {
perror("open");
return -1;
}
// 拓展文件长度
int ret = lseek(fd, 100, SEEK_END);
if (ret == -1) {
perror("lseek");
return -1;
}
// 写入空数据
write(fd, " ", 1);
// 关闭文件
close(fd);
return 0;
}
文件权限查询
/*
#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", W_OK);
if (ret == -1) {
perror("access");
}
printf("文件可写!\n");
return 0;
}
文件权限修改
/*
#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", 0775);
if (ret == -1) {
perror("access");
return -1;
}
return 0;
}
文件尺寸修改
/*
#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("access");
}
return 0;
}
文件信息获取
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
作用:获取文件相关的信息
参数:
- pathname:文件路径
- statbuf:结构体变量指针,传出参数,用于保存获取到的文件信息
返回值:成功则返回0,失败则返回-1,并设置errno
int lstat(const char *pathname, struct stat *statbuf);
参数:
- pathname:文件路径
- statbuf:结构体变量指针,传出参数,用于保存获取到的文件信息
返回值:成功则返回0,失败则返回-1,并设置errno
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
int main(){
struct stat statbuf;
int ret = stat("a.txt", &statbuf);
if (ret == -1) {
perror("stat");
return -1;
}
printf("size:%ld\n", statbuf.st_size);
return 0;
}
笔记
![](https://img-blog.csdnimg.cn/b29f6c77c21e47569a6be8d92102fa85.png)
![](https://img-blog.csdnimg.cn/e8a125e213ee438097e64551006e4965.png)
模拟ls -l指令
// 模拟实现ls -l指令
// -rw-rw-r-- 1 carrot carrot 13 4月 4 15:45 a.txt
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>
int main(int argc, char* argv[]){
if (argc < 2) {
std::cout << argv[0] << " filename" << std::endl;
return -1;
}
struct stat statbuf;
int ret = stat(argv[1], &statbuf);
if (ret == -1) {
perror("stat");
return -1;
}
// 获取文件类型和文件权限
char perms[11] = {0}; // 用于保存文件类型和文件权限的字符串
switch (statbuf.st_mode & S_IFMT)
{
case S_IFLNK:
perms[0] = 'l';
break;
case S_IFDIR: // 目录
perms[0] = 'd';
break;
case S_IFREG: // 普通文件
perms[0] = '-';
break;
case S_IFBLK: // 块文件
perms[0] = 'b';
break;
case S_IFCHR: // 字符设备
perms[0] = 'c';
break;
case S_IFSOCK: // 套接字
perms[0] = 'S';
break;
case S_IFIFO: // 管道
perms[0] = 'p';
break;
default:
perms[0] = '?';
break;
}
// 文件所有者
perms[1] = (statbuf.st_mode & S_IRUSR ? 'r' : '-');
perms[2] = (statbuf.st_mode & S_IWUSR ? 'w' : '-');
perms[3] = (statbuf.st_mode & S_IXUSR ? 'x' : '-');
// 文件所在组
perms[4] = (statbuf.st_mode & S_IRGRP ? 'r' : '-');
perms[5] = (statbuf.st_mode & S_IWGRP ? 'w' : '-');
perms[6] = (statbuf.st_mode & S_IXGRP ? 'x' : '-');
perms[7] = (statbuf.st_mode & S_IROTH ? 'r' : '-');
perms[8] = (statbuf.st_mode & S_IWOTH ? 'w' : '-');
perms[9] = (statbuf.st_mode & S_IXOTH ? 'x' : '-');
// 获取硬链接数
int linkNum = statbuf.st_nlink;
// 文件所有者
char *fileUser = getpwuid(statbuf.st_uid)->pw_name;
// 文件所在组
char *fileGrp = getgrgid(statbuf.st_gid)->gr_name;
// 文件大小
long int filesize = statbuf.st_size;
// 获取修改时间
char *time = ctime(&statbuf.st_mtim.tv_sec); // 最后带一个回车
char mtime[512] = {0};
strncpy(mtime, time, strlen(time) - 1);
char buf[1024] = {0};
sprintf(buf, "%s %d %s %s %ld %s %s", perms, linkNum, fileUser, fileGrp, filesize, mtime, argv[1]);
std::cout << buf <<std::endl;
return 0;
}
目录的创建
/*
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
作用:创建目录
- pathname:创建的目录名称
- mode:权限,8进制数
返回值:成功返回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;
}
目录的修改
/*
#include <unistd.h>
int chdir(const char *path);
- 作用:修改进程工作目录
- 参数:
- path:需要修改的工作目录
#include <unistd.h>
char *getcwd(char *buf, size_t size);
- 作用:获取当前工作目录
- 参数:
- buf:保存的路径,指向的是一个数组
- size:数组的大小
- 返回值:
返回的指向的一块内存,这个数据就是第一个参数
*/
#include <unistd.h>
#include <stdio.h>
int main(){
// 获取当前的工作目录
char buf[128];
getcwd(buf, sizeof(buf));
printf("当前的工作目录是:%s\n", buf);
// 修改工作目录
int ret = chdir("../copy");
// 获取当前的工作目录
getcwd(buf, sizeof(buf));
printf("当前的工作目录是:%s\n", buf);
return 0;
}
目录重命名
/*
#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("mkdir");
return -1;
}
return 0;
}
目录的打开、遍历、关闭
/*
#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 <stdlib.h>
#include <string.h>
// 读取某个目录下所有的普通文件个数
// ./a.out dirname
int getFileNum(const char *path);
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("%s path\n", argv[0]);
return -1;
}
int total = getFileNum(argv[1]);
printf("普通文件的个数为:%d\n", total);
return 0;
}
// 用户获取目录下所有普通文件的个数
int getFileNum(const char *path) {
// 打开目录
DIR *dir = opendir(path);
if (dir == NULL) {
perror("opendir");
printf("%s\n", path);
exit(0);
}
// 记录普通文件个数
int total;
struct dirent *ptr;
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);
} else if (ptr->d_type == DT_REG) {
// 普通文件
total++;
}
}
closedir(dir);
return total;
}
笔记
![](https://img-blog.csdnimg.cn/c25788e4874b4a42860dbe0f3297c08c.png)
dup
/*
#include <unistd.h>
int dup(int oldfd);
复制一个新的文件描述符
参数:
- oldfd 需要复制的文件的描述符
int dup2(int oldfd, int newfd);
*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.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!";
int ret = write(fd1, str, strlen(str));
if (ret == -1) {
perror("write");
return -1;
}
return 0;
}
dup2
/*
#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 <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
int main() {
int fd1 = open("1.txt", O_RDWR | O_CREAT, 0664);
if (fd1 == -1) {
perror("open");
return -1;
}
int fd2 = open("2.txt", O_RDWR | O_CREAT, 0664);
if (fd2 == -1) {
perror("open");
return -1;
}
printf("fd1 : %d, fd2 : %d\n", fd1, fd2);
int fd3 = dup2(fd1, fd2);
if (fd3 == -1) {
perror("dup2");
return -1;
}
// 使用fd3去写数据,实际操作的是1.txt,不是2.txt
char *str = "hello,world!";
int len = write(fd2, str, strlen(str));
if (len == -1) {
perror("write");
return -1;
}
printf("fd1 : %d, fd2 : %d, fd3 : %d\n", fd1, fd2, fd3);
close(fd1);
close(fd2);
return 0;
}
文件描述符复制、文件flag修改
/*
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... );
参数
- fd:需要操作文件的描述符
- cmd:表示对文件描述符的操作内容
- F_DUPFD 复制文件描述符,复制第一个 参数,得到一个新的文件描述符(返回值)
int fd1 = fcntl(fd, F_DUPFD);
- F_GETFL 获取指定文件描述文件的状态flag
文件状态flag和通过open函数传递的flag相同
- F_SETFL 设置文件描述符文件的状态flag
必选项 O_RDONLY, O_WRONLY, ORDWR 不可以被修改
可选项 O_APPEND, O_NONBLOCK
- O_APPEND 表示追加数据
- O_NONBLOCK 设置成不阻塞
阻塞和非阻塞
描述的是函数调用的行为。
*/
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main() {
// 复制文件描述符
// int fd = open("1.txt", O_RDONLY);
// int ret = fcntl(fd, F_DUPFD);
// 修改、获取文件的flag
int fd = open("1.txt", O_RDWR); // 如果是使用O_RDONLY打开文件,后面设置了O_APPEND也无法进行追加
if (fd == -1) {
perror("open");
return -1;
}
int flag = fcntl(fd, F_GETFL);
if (flag == -1) {
perror("fcntl-F_GETFL");
return -1;
}
int ret = fcntl(fd, F_SETFL, O_APPEND | flag);
if (ret == -1) {
perror("fcntl-F_SETFL");
return -1;
}
// 写入数据
const char * str = "nihao";
write(fd, str, strlen(str));
close(fd);
return 0;
}