1 open打开文件
- 打开文件
int open(const char *pathname, int flags);
- 创建文件
int open(const char *pathname, int flags);
- 关闭文件
int close(int fd);
不是重载,C语言不支持重载,是可变参数
open.c
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 函数声明在<fcntl.h>,与flag有关的宏定义在了<sys/types.h>,<sys/stat.h>中
// 打开一个已经存在的文件
int open(const char *pathname, int flags);
参数:
- pathname:要打开的文件路径
- flags:对文件的操作权限设置还有其他的设置
O_RDONLY, O_WRONLY, O_RDWR 这三个设置是互斥的
返回值:返回一个新的文件描述符,如果调用失败,返回-1(此时,errno会被设置成合适的值)
errno:属于Linux系统函数库,库里面的一个全局变量,记录的是最近的错误号。
#include <stdio.h>
void perror(const char *s);
作用:打印errno对应的错误描述
s参数:用户描述,比如hello,最终输出的内容是 hello:xxx(实际的错误描述)
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
// 打开一个文件
int fd = open("a.txt", O_RDONLY);
if(fd == -1) {
perror("尝试打开文件");
}
// 读写操作
// 关闭
close(fd);
return 0;
}
运行示例代码。
root@LDY:~/cpp-study/lesson09# gcc open.c -o open
root@LDY:~/cpp-study/lesson09# ./open
尝试打开文件: No such file or directory
2 open创建新文件
create.c
/*
#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:八进制的数,表示创建出的新的文件的操作权限,比如:0777,
最终的权限是:mode & ~umask
0777 -> 111111111
& 0775 -> 111111101
----------------------------
111111101
按位与:0和任何数都为0
umask的作用就是抹去某些权限。
本例中,传入0777,umask为0002,最终结果是0775
flags参数是一个int类型的数据,占4个字节,32位。
flags 32个位,每一位就是一个标志位。
(每一种标记都有一位对应1,所以用按位或"|"能实现标记的组合)
... 0 0 0 1
| ... 0 0 1 0
--------------
... 0 0 1 1
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
// 创建一个新的文件
int fd = open("create.txt", O_RDWR | O_CREAT, 0777);
if(fd == -1) {
perror("open");
}
// 关闭
close(fd);
return 0;
}
查看当前的umask。
root@LDY:~/cpp-study/lesson09# umask
0022
运行示例代码。
root@LDY:~/cpp-study/lesson09# gcc create.c -o create
root@LDY:~/cpp-study/lesson09# ./create
root@LDY:~/cpp-study/lesson09# ll create.txt
-rwxr-xr-x 1 root root 0 Oct 24 21:57 create.txt*
3 read、write函数
- 读文件
ssize_t read(int fd, void *buf, size_t count);
- 写文件
ssize_t write(int fd, const void *buf, size_t count);
copyfile.c
文件复制示例。
/*
#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:文件描述符,open得到的,通过这个文件描述符操作某个文件
- buf:要往磁盘写入的数据,数组
- count:要写的数据的实际的大小
返回值:
成功:实际写入的字节数
失败:返回-1,并设置errno
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
// 1.通过open打开English.txt文件
int srcfd = open("example.txt", O_RDONLY);
if(srcfd == -1) {
perror("open");
return -1;
}
// 2.创建一个新的文件(拷贝文件)
int destfd = open("cpy.txt", O_WRONLY | O_CREAT, 0664);
if(destfd == -1) {
perror("open");
return -1;
}
// 3.频繁的读写操作
char buf[1024] = {0};
int len = 0;
while((len = read(srcfd, buf, sizeof(buf))) > 0) {
write(destfd, buf, len);
}
// 4.关闭文件
close(destfd);
close(srcfd);
return 0;
}
运行示例代码。
root@LDY:~/cpp-study/lesson10# gcc copyfile.c -o copy
root@LDY:~/cpp-study/lesson10# ./copy
root@LDY:~/cpp-study/lesson10# tree
.
├── copy
├── copyfile.c
├── cpy.txt
└── example.txt
4 lseek函数
- 文件指针偏移
off_t lseek(int fd, off_t offset, int whence);
lseek.c
文件扩容示例。
/*
标准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);
参数:
- fd:文件描述符,通过open得到的,通过这个fd操作某个文件
- 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, 增加了100个字节
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;
}
运行前后文件大小变换。
-rw-r--r-- 1 root root 11 Oct 25 20:29 hello.txt
-rw-r--r-- 1 root root 112 Oct 25 20:36 hello.txt
5 stat、lstat函数
- 获取文件信息
int stat(const char *pathname, struct stat *statbuf);
- 获取软连接文件信息
int lstat(const char *pathname, struct stat *statbuf);
- stat结构体
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; // 设备文件的设备编号 off_t st_size; // 文件字节数(文件大小) blksize_t st_blksize; // 块大小 blkcnt_t st_blocks; // 块数 time_t st_atime; // 最后一次访问时间 time_t st_mtime; // 最后一次修改时间 time_t st_ctime; // 最后一次改变时间(指属性) };
stat.c
/*
#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;
}
运行示例代码。
root@LDY:~/cpp-study/lesson12# gcc stat.c -o stat
root@LDY:~/cpp-study/lesson12# ./stat
size: 11
- st_mode变量
6 案例:模拟ls -l
命令
参考链接
https://www.nowcoder.com/study/live/504/1/24