zoukankan      html  css  js  c++  java
  • Unix/Linux系统编程-学习笔记-第八章

    第八章 使用系统调用进行文件操作

    8.1 系统调用

    在操作系统中,进程以两种不同的模式运行,即内核模式和用户模式,简称Kmode和Umode。在Umode中,进程的权限非常有限。它不能执行任何需要特殊权限的操作。特殊权限的操作必须在Kmode下执行。系统调用(简称syscall)是一种允许进程进入Kmode以执行Umode不允许操作的机制。复刻子进程、修改执行映像,甚至是终止等操作都必须在内核中执行。

    8.2 系统调用手册页

    在Unix以及大多版本的Linux中,在线手册页保存在/usr/man/目录中(Goldt等1995;Kerrisk 2010,2017)。而在Ubuntu Linux中,则保存在/usr/share/man目录中。man2子目录中列出了所有系统调用手册页。sh命令man 2 NAME显示了系统调用名称的手册页。
    例如:

    man 2 stat
    man 2 open
    man 2 read
    

    许多系统调用需要特别包含头文件,手册页的SYNOPSIS(概要)部分列出来这些文件。如果没有合适的头文件,会有警告。

    8.3 使用系统调用进行文件操作

    系统调用必须由程序发出。它们的用法就像普通函数调用一样。每个系统调用都是一个库函数,它汇集系统调用参数,并最终向操作系统内核发出一个系统调用。

    8.4 常规的系统调用

    文件操作的系统调用:
    stat:获取文件状态信息

    int stat(char *filename, struct stat *buf);
    int fstat(int filedes, struct stat *buf);
    int lstat(char *filename, struct stat *buf);
    

    open:打开一个文件进行读、写、追加

    int open(char *file, int flags, int mode);
    

    close:关闭打开的文件描述符

    int close(int fd);
    

    read:读取打开的文件描述符

    int read(int fd, char buf[], int count);
    

    write:写入打开的文件描述符

    int write(int fd, char buf[], int count);
    

    lseek:重新定位文件描述符的读/写偏移量

    int lseek(int fd, int offset, int whence);
    

    dup:将文件描述符复制到可用的最小描述符编号中

    int dup(int oldfd);
    

    dup2:将oldfd复制到newfd中,如果文件链接数为0,则删除文件

    int dup2(int oldfd, int newfd);
    

    link:将新文件硬链接到旧文件

    int link(char *oldPath, char *newPath);
    

    unlink:取消某个文件的链接;如果文件链接数为0,则删除文件

    int unlink(char *pathname);
    

    symlink:创建一个符号链接

    int symlink(char *target, char *newpath);
    

    readlink:读取符号链接文件的内容

    int readlink(char *path, char *buf, int bufsize);
    

    umask:设置文件创建掩码;文件权限为(mask & ~umask)

    int umask(int umask);
    

    8.5 链接文件

    在Unix/Linux中,每个文件都有一个路径名。但是,Unix/Linux允许使用不同的路径名来表示用一个文件。这些文件叫作LINK(链接)文件。有两种类型的链接,即硬链接和软链接或符号链接。

    8.5.1 硬链接文件

    硬链接:命令

    ln oldpath newpath
    

    创建从newpath到oldpath的硬链接。对应的系统调用为:

    link(char *oldpath, char *newpath)
    

    硬链接文件会共享文件系统中相同的文件表示数据结构(索引节点)。文件链接数会记录链接到同一索引节点的硬链接数量。硬链接仅适用于非目录文件。否则,它可能会在文件系统名称空间中创建循环,这是不允许的。相反,系统调用:

    unlink(char *pathname)
    

    会减少文件的链接数。如果链接数变为0,文件会被完全删除。这就是rm(file)命令的作用。如果某个文件包含非常重要的信息,就最好创建多个链接到文件的硬链接,以防被意外删除。

    8.5.2 符号链接文件

    软链接:命令

    ln -s oldpath newpath   # ln command with the -s flag
    

    创建从newpath到oldpath的软链接或符号链接。对应的系统调用是:

    symlink(char *oldpath, char *newpath)
    

    newpath是LNK类型的普通文件,包含oldpath字符串。它可作为一个绕行标志,使访问指向链接好的目标文件。与硬链接不同,软链接适用于任何文件,包括目录。软链接在以下情况下非常有用。
    (1)通过一个较短的名称来访问一个经常使用的较长的路径名称,例如:

    x -> aVeryLongPathnameFile
    

    (2)将标准动态库名称链接到实际版本的动态库,例如:

    libc.so.6 -> libc.2.7.so
    

    当将实际动态库更改为不同版本时,库安装程序只需更改(软)链接以指向新安装的库。
    软链接的一个缺点是目标文件可能不复存在了。如果是这样,绕行标志可能引导可怜的司机摔下悬崖。在Linux中,会通过ls命令以适当的深色RED显示此类危险,提醒用户链接已断开。此外,如果foo -> /a/b/c是软链接,open("foo", 0)系统调用将打开被链接的文件/a/b/c,而不是链接文件自身。所以open()/read()系统调用不能读取软链接文件,反而必须要用readlink系统调用来读取软链接文件的内容。

    8.6 stat系统调用

    stat/lstat/fstat系统调用可将一个文件的信息返回。命令man 2 stat会显示stat系统调用的手册页。

    8.6.5 opendir-readdir函数

    目录也是一个文件。我们应该能像其他任何普通文件一样,打开一个READ目录,然后读取和显示它的内容。然而,根据文件系统的不同,目录文件的内容可能会有不同。因此,用户可能无法正确读取和解释目录的内容。鉴于此,POSIX为目录文件指定了以下接口函数。

    #include <dirent.h>
    DIR *open(dirPath);     // open a directory named dirPath for READ
    struct dirent *readdir(DIR *dp);    // return a dirent pointer
    

    Linux中dirent结构体是:

    struct dirent {
        u32 d_ino;  // inode number
        u16 d_reclen;
        char d_name[];
    };
    

    在dirent结构体中,POSIX只要求必须保留d_name字段。其他字段取决于具体的系统。
    opendir()返回一个DIR指针dirp。每个readdir(dirp)调用返回一个dirent指针,指向目录中下一个条目的dirent结构体。当目录中没有更多条目时,则返回一个NULL指针。我们用一个例子来说明它们的用法。下面的代码段可打印目录中的所有文件名称。

    #include <dirent.h>
    struct dirent *ep;
    DIR *dp = opendir("dirname");
    while (ep = readdir(dp)) {
        printf("name=%s ", ep->d_name);
    }
    

    8.6.6 readlink函数

    Linux的open()系统调用遵循符号链接。因此,无法打开符号链接文件并读取其内容。
    要想读取符号链接文件的内容,我们必须使用readlink系统调用,即:

    int readlink(char *pathname, char buf[], int bufsize);
    

    它将软链接文件的内容复制到bufsize的buf[]中,并将实际复制的字节数返回。

    8.7.1 打开文件和文件描述符

    #include <sys/type.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int open(char *pathname, int flags, mode_t mode);
    

    open()打开一个文件进行读、写或追加。它会返回一个进程可用的最小文件描述符,用于后续的read()、write()、lseek()和close()系统调用。标志字段必须包含下列一种访问模式、即O_RDONLY、O_WRONLY或者O_RDWR。此外,这些标志可与其他标志(O_APPEND、O_TRUNC、O_CLOEXEC)逐位进行OR组合。

    ———————————————————————————————————————————————————————————————— 转载麻烦附上本文链接和本声明,感谢! 博主<叶家星>博客园链接如下:https://www.cnblogs.com/yejiaxing-01/
  • 相关阅读:
    linux下进度条的简单实现
    简单vim配置
    Linux下find指令
    Python学习笔记十三_操作数据库
    Python学习笔记十二_常用模块
    Python学习笔记十一_函数返回多值、列表生成式、循环多变量、入参格式声明
    Python学习笔记十_模块、第三方模块安装、模块导入
    Python函数及json练习_双色球
    Python函数及json练习_商品管理
    Python json练习_读写文件函数
  • 原文地址:https://www.cnblogs.com/yejiaxing-01/p/15376447.html
Copyright © 2011-2022 走看看