导航

文件系统

Posted on 2023-06-16 20:58  koodu  阅读(28)  评论(0编辑  收藏  举报

用户态和内核态

运行在内核态的进程可以毫无限制的访问各种资源,而在用户态下的用户进程的各种操作都有着限制,比如不能随意的访问内存、不能开闭中断以及切换运行的特权级别。

操作系统一般是通过软件中断从用户态切换到内核态。

函数工作流程

虚拟地址空间

每个进程都会分配虚拟地址空间,在32位机器上,该地址空间为4G。

当应用程序使用虚拟地址访问内存时,处理器(CPU)会将其转化成物理地址(MMU)。MMU:将虚拟的地址转化为物理地址。

文件描述符

//这三个默认打开,所以后面的文件描述符从3开始
#define STDIN_FILENO  0 //标准输入的文件描述符
#define STDOUT_FILENO 1 //标准输出的文件描述符
#define STDERR_FILENO 2 //标准错误的文件描述符

在程序运行起来后打开其他文件时,系统会返回文件描述符表中最小可用的文件描述符,并将此文件描述符记录在表中。

Linux 中一个进程最多只能打开 NR_OPEN_DEFAULT (即1024)个文件,故当文件不再使用时应及时调用 close() 函数关闭文件。

文件io函数

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);
功能:
    打开文件,如果文件不存在则可以选择创建。
参数:
    pathname:文件的路径及文件名
    flags:打开文件的行为标志,必选项 O_RDONLY, O_WRONLY, O_RDWR
    mode:这个参数,只有在文件不存在时有效,指新建文件时指定文件的权限
返回值:
    成功:成功返回打开的文件描述符
    失败:-1
O_RDONLY 以只读的方式打开
O_WRONLY 以只写的方式打开
O_RDWR 以可读、可写的方式打开

可选项,和必选项按位或起来

取值 含义
O_CREAT 文件不存在则创建文件,使用此选项时需使用mode说明文件的权限
O_EXCL 如果同时指定了O_CREAT,且文件已经存在,则出错
O_TRUNC 如果文件存在,则清空文件内容
O_APPEND 写文件时,数据添加到文件末尾
O_NONBLOCK 对于设备文件, 以O_NONBLOCK方式打开可以做非阻塞I/O
write()
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:
    把指定数目的数据写到文件(fd)
参数:
    fd :  文件描述符
    buf : 数据首地址
    count : 写入数据的长度(字节)
返回值:
    成功:实际写入数据的字节个数
    失败: - 1
read()

#include <unistd.h>
​
ssize_t read(int fd, void *buf, size_t count);
功能:
    把指定数目的数据读到内存(缓冲区)
参数:
    fd : 文件描述符
    buf : 内存首地址
    count : 读取的字节个数
返回值:
    成功:实际读取到的字节个数
    失败: - 1
阻塞与非阻塞

阻塞与非阻塞是对于文件而言的,而不是指read、write等的属性。

非阻塞读取一个文件时:如果为非阻塞,但是没有数据可读,此时全局变量 errno 被设置为 EAGAIN

lseek()

#include <sys/types.h>
#include <unistd.h>
​
off_t lseek(int fd, off_t offset, int whence);
功能:
    改变文件的偏移量
参数:
    fd:文件描述符
    offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。
​
    whence:其取值如下:
        SEEK_SET:从文件开头移动offset个字节
        SEEK_CUR:从当前位置移动offset个字节
        SEEK_END:从文件末尾移动offset个字节
返回值:
    若lseek成功执行, 则返回新的偏移量
    如果失败, 返回-1
stat()
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
​
int stat(const char *path, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
功能:
    获取文件状态信息
    stat和lstat的区别:
        当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;
        而stat返回的是该链接指向的文件的信息。
参数:
    path:文件名
    buf:保存文件信息的结构体
返回值:
    成功: 0
    失败: -1
struct stat结构体
struct stat {
    dev_t           st_dev;     //文件的设备编号
    ino_t           st_ino;     //节点
    mode_t          st_mode;            //文件的类型和存取的权限
    nlink_t         st_nlink;       //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t           st_uid;     //用户ID
    gid_t           st_gid;     //组ID
    dev_t           st_rdev;        //(设备类型)若此文件为设备文件,则为其设备编号
    off_t           st_size;        //文件字节数(文件大小)
    blksize_t       st_blksize;     //块大小(文件系统的I/O 缓冲区大小)
    blkcnt_t        st_blocks;      //块数
    time_t          st_atime;       //最后一次访问时间
    time_t          st_mtime;       //最后一次修改时间
    time_t          st_ctime;       //最后一次改变时间(指属性)
};
chmod()

#include <sys/stat.h>
​
int chmod(const char *pathname, mode_t mode);
功能:修改文件权限
参数:
    filename:文件名
    mode:权限(8进制数)
返回值:
    成功:0
    失败:-1
chown()

#include <unistd.h>
​
int chown(const char *pathname, uid_t owner, gid_t group);
功能:修改文件所有者和所属组
参数:
    pathname:文件或目录名
    owner:文件所有者id,通过查看 /etc/passwd 得到所有者id
    group:文件所属组id,通过查看 /etc/group 得到用户组id
返回值:
    成功:0
    失败:-1

文件描述符复制

dup() 和 dup2()都是用来复制一个文件的描述符,使新的文件描述符也标识旧的文件描述符所标识的文件。

dup()
#include <unistd.h>
​
int dup(int oldfd);
功能:
    通过 oldfd 复制出一个新的文件描述符,新的文件描述符是调用进程文件描述符表中最小可用的文件描述符,最终 oldfd 和新的文件描述符都指向同一个文件。
参数:
    oldfd : 需要复制的文件描述符 oldfd
返回值:
        成功:新文件描述符
        失败: -1
dup2()
#include <unistd.h>
​
int dup2(int oldfd, int newfd);
功能:
    通过 oldfd 复制出一个新的文件描述符 newfd,如果成功,newfd 和函数返回值是同一个返回值,最终 oldfd 和新的文件描述符 newfd 都指向同一个文件。
参数:
    oldfd : 需要复制的文件描述符
    newfd : 新的文件描述符,这个描述符可以人为指定一个合法数字(0 - 1023),如果指定的数字已经被占用(和某个文件有关联),此函数会自动关闭 close() 断开这个数字和某个文件的关联,再来使用这个合法数字。
返回值:
    成功:返回 newfd
    失败:返回 -1
fcntl()
#include <unistd.h>
#include <fcntl.h>
​
int fcntl(int fd, int cmd, ... /* arg */);
功能:改变已打开的文件性质,fcntl针对描述符提供控制。
参数:
    fd:操作的文件描述符
    cmd:操作方式
    arg:针对cmd的值,fcntl能够接受第三个参数int arg。
返回值:
    成功:返回某个其他值
    失败:-1
fcntl函数有5种功能:

1) 复制一个现有的描述符(cmd=F_DUPFD)

2) 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)

3) 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL)

4) 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)

5) 获得/设置记录锁(cmd=F_GETLK, F_SETLK或F_SETLKW)
fcntl()将描述符fd设为非阻塞
  int flags=fcntl(fd,F_GETFL);//获取状态
  flags|=O_NONBLOCK;
  fcntl(fd,F_SETFL,flags);
 fcntl(fd, F_SETFL, O_NONBLOCK );