项目学习地址:【牛客网C++服务器项目学习】
day04
1.open函数
open函数在Linux下一般用来打开或者创建一个文件,我们可以根据参数来定制我们需要的文件的属性和用户权限等各种参数。
- open函数定义:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
- 返回值
open函数的返回值如果操作成功,它将返回一个文件描述符,如果操作失败,它将返回-1。
- 参数含义:
- pathname:
在open函数中第一个参数pathname是指向想要打开的文件路径名,或者文件名。我们需要注意的是,这个路径名是绝对路径名。文件名则是在当前路径下的。
2、flags:
flags参数表示打开文件所采用的操作,我们需要注意的是:必须指定以下三个常量的一种,且只允许指定一个
O_RDONLY:只读模式
O_WRONLY:只写模式
O_RDWR:可读可写
以下的常量是选用的,这些选项是用来和上面的必选项进行按位或起来作为flags参数。
O_APPEND 表示追加,如果原来文件里面有内容,则这次写入会写在文件的最末尾。
O_CREAT 表示如果指定文件不存在,则创建这个文件
O_EXCL 表示如果要创建的文件已存在,则出错,同时返回 -1,并且修改 errno 的值。
O_TRUNC 表示截断,如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode)
以下三个常量同样是选用的,它们用于同步输入输出
O_DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下,不等待文件属性更新。
O_RSYNC read 等待所有写入同一区域的写操作完成后再进行
O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/O
3、mode:
mode参数表示设置文件访问权限的初始值,和用户掩码umask(初始值一般为0002)有关,比如0644表示-rw-r–r–,也可以用S_IRUSR、S_IWUSR等宏定义按位或起来表示,详见open(2)的Man Page。要注意的是,有以下几点
- 文件权限由open的mode参数和当前进程的umask掩码共同决定。
- 第三个参数是在第二个参数中有O_CREAT时才作用,如果没有,则第三个参数可以忽略
文件权限。r:可读,w:可写,x:可执行。三个一组,第一组为当前用户,第二组为用户所在组,第三组是其他组
open函数与fopen函数区别
从来源来分,这两者很好区分:
open函数是Unix下系统调用函数,操作成功返回的是文件描述符,操作失败返回的是-1,
fopen是ANSIC标准中C语言库函数,所以在不同的系统中调用不同的内核的API,返回的是一个指向文件结构的指针。
同时open函数没有缓冲,fopen函数有缓冲,open函数一般和write配合使用,fopen函数一般和fwrite配合使用。
2. read、write函数
- read函数
#include <unistd.h>
int read(int filedes, void *buff, int nbytes) ;//(文件描述符, 将读取的数据放到该地址, 将要读取的数据大小)
返回:实际读到的字节数,若已到文件尾为0,若出错为- 1。读出来的数据不会再末尾加’\0’,和fread()不同。
- write函数
#include <unistd.h>
int write(int filedes, const void * buff, int nbytes) ;//(文件描述符, 将写入的数据地址, 将要写入的数据大小)
返回:若成功为已写的字节数,若出错为- 1
-
write()函数返回值一般无0,只有当如下情况发生时才会返回0:write(fp, p1+len, (strlen(p1)-len)中第三参数为0,此时write()什么也不做,只返回0。
-
write()函数从buf写数据到fd中时,若buf中数据无法一次性读完,那么第二次读buf中数据时,其读位置指针(也就是第二个参数buf)不会自动移动,需要程序员编程控制;
-
在write第三参数count大小最好为buf中数据的大小,以免出现错误。
3.lseek函数
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
lseek 主要作用是移动文件读写指针
参数:
fd 表示要操作的文件描述符
offset是相对于whence(基准)的偏移量
whence 可以是SEEK_SET(文件指针开始),SEEK_CUR(文件指针当前位置) ,SEEK_END为文件指针尾
返回值:
文件读写指针距文件开头的字节大小,出错,返回-1
lseek函数的几种用法
//1.获取文件长度
off_t length = lseek(fd, 0, SEEK_END);
//2.获取当前指针位置
off_t currPos = lseek(fd, 0, SEEK_CUR);
//3.移动指针到文件头部
off_t currPos = lseek(fd, 0, SEEK_SET);
//4.拓展文件长度
off_t pos = lseek(fd, n, SEEK_END);
//做一次写操作
write(fd, buff, sizeof(buff));
4.stat函数
表头文件: #include <sys/stat.h>
#include <unistd.h>
定义函数: int stat(const char *file_name, struct stat *buf);
函数说明: 通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值: 执行成功则返回0,失败返回-1,错误代码存于errno
错误代码:
ENOENT 参数file_name指定的文件不存在
ENOTDIR 路径中的目录存在但却非真正的目录
ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接
EFAULT 参数buf为无效指针,指向无法存在的内存空间
EACCESS 存取文件时被拒绝
ENOMEM 核心内存不足
ENAMETOOLONG 参数file_name的路径名称太长
stat函数是对本文件进行文件属性信息获取,还有一个lstat函数,是对链接文件的属性获取
(感觉这一节有些水时长,讲得这么细分,不利于做这个项目)
5.模拟实现ls -l命令
这一节没有怎么看,主要内容是利用stat函数获取文件的信息,并按照ls命令格式化打印输出相关信息
练习使用stat函数和打印输出的条件处理,有兴趣的同学可以跟着做一下
6.文件属性相关的操作函数
-
access函数
-
函数功能:检查调用进程是否可以对指定的文件执行某种操作
-
需要包含的头文件
#include <stdio.h>
#include <unistd.h>
-
函数:
int access(const char * pathname, int mode)
-
参数:mode
-
R_OK:读权限
-
W_OK:写权限
-
X_OK:执行权限
-
F_OK:是否存在
-
-
-
返回值:成功返回0,失败返回-1,同时errno会被设置为合适值。
-
-
chmod函数
- 函数功能:修改文件权限
- 需要包含的头文件
#include<sys/stat.h>
-
函数:
int chmod(const char *filename,int mode)
-
参数:mode
- 权限制,对应的8进制数,最高权限设置为0777
-
-
返回值:成功返回0,失败返回-1,同时errno会被设置为合适值。
-
chown函数
-
函数功能:修改文件所有者和所属组。
-
需要包含的头文件
#include<unistd.h>
-
函数:
int chown(const char *path,uid_t owner,gid_t group)
-
返回值:成功返回0,失败返回-1,同时errno会被设置为合适值。
-
-
truncate函数
-
函数功能:修改文件大小。
-
需要包含的头文件
#include<unistd.h>
#include<sys/types.h>
-
函数:
int truncate(const char *path,off_t length)
- 参数: path为文件名,length为为文件的最终大小。off_t为长整型,long int。
(1)最终大小比原来大,向后扩展,自动填充字符’\0’。
(2)最终大小比原来小,删除后边的部分。
- 参数: path为文件名,length为为文件的最终大小。off_t为长整型,long int。
-
返回值:成功返回0,失败返回-1,同时errno会被设置为合适值。
-
7.目录操作函数
-
mkdir
-
rmdir
-
rename
-
chdir
-
getcwd
这一讲比较简单,终端shell的几个函数实现,看一下就会了。
8.目录遍历函数
-
opendir
-
readdir
-
closedir
这一讲写的这个程序真的很有意思。建议大家关掉视频,自己动手撸,在shell终端上,通过man
命令查看函数的参数、返回值、宏定义等。撸不对的时候,再去看老师写的代码。
对了,如果你在终端上输入:man 3 opendir
系统显示没有该手册的话,是因为你没有安装这部分的手册资料
输入以下命令进行安装:sudo apt-get install manpages-posix-dev
9.文件描述符操作函数
int dup(int oldfd);
int dup2(int oldfd, int newfd);
dup()和dup2()函数都可以用来复制一个文件描述符
dup()函数返回的新的文件描述符是当前可用文件描述符中最小数值。复制文件描述符,实质应该理解为:fd句柄原本指向test.file的文件描述结构体,dup()指向完毕后,new_fd句柄也会指向test.file文件描述结构体。所以说对new_fd句柄所指的文件操作,等价于操作test_file文件。
dup2()与dup()的区别在于可以用newfd来指定新描述符数值,若newfd指向的文件已经被打开,会先将其关闭。若newfd等于oldfd,就不关闭newfd,newfd和oldfd共同指向一份文件。
10.fcntl函数
功能描述:根据文件描述词来操作文件的特性。
详细内容可以查看这篇文章:Linux fcntl 函数详解