Linux系统函数

请注意,本文编写于 93 天前,最后修改于 93 天前,其中某些信息可能已经过时。

Linux系统函数

  1. C库IO函数工作流程

    1. FILE*

      1. 文件描述符

        1. 通过文件描述符找到磁盘文件的位置
      2. 文件读写位置指针

        1. 文件打开之后会有一个文件指针指向文件起始位置
      3. IO缓冲区

        1. 为什么会有缓冲区

          1. 因为访问机械硬盘速度会很慢寻道是毫秒级的
          2. 而内存读写速度是纳秒级别的
          3. 所以在内存中提供缓冲区,减少磁盘访问次数
        2. 什么时候把缓冲区(内存中)的数据刷到硬盘上

          1. fflush刷新缓冲区
          2. 缓冲区已满
          3. 正常关闭文件(fclose/return(mian函数)/exit(main函数))
  2. PCB进程控制块

    1. PCB在虚拟空间的内核区
    2. PCB进程控制块中有一个文件描述符表

      1. 其实是个数组,数组大小0-1023
      2. 用户可以打开的是1024-3,因为前三个默认打开作为标准输入、标准输出、标准错误
      3. 没打开一个新文件,则占用一个文件描述符,而且使用的是空闲的最小的一个文件描述符
    3. PCB里面还包含了其他的信息
  3. 虚拟地址空间

    1. 虚拟空间是进程在运行时32位系统给程序分配的0-4G的空间

      1. 用户空间0-3G

        1. 0-4k受保护的地址(void *)
        2. main在text代码段、
        3. 初始化全局变量、未初始化全局变量
        4. 栈空间(内存从上往下增长)
        5. malloc堆空间(内存从下往上增长)
        6. 动态库(共享库)空间

          1. 调用C标准函数
          2. 调用的C标准函数时,加载封装好的lib动态库
          3. 在共享区那块空闲的空间加载动态库

            1. 所以动态库的起始地址是不固定的
            2. 所以生成代码的时候就要生成与位置无关的代码(相对的地址)
        7. 命令行参数

          1. int main(int argc, char *argv[])
        8. 环境变量

          1. 在命令行输入env就可以查看所有环境变量
      2. 3-4G属于内核空间

        1. 内存管理
        2. 进程管理
        3. 设备驱动管理
        4. vfs虚拟文件系统
        5. ....
    2. Linux可执行程序格式ELF

      1. ELF段
      2. .bss/.data/.text
    3. 什么需要虚拟内存空间

      1. 方便编译器和操作系统安排程序地址分布

        1. 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区
      2. 方便进程之间的隔离

        1. 不同进程使用的虚拟地址彼此隔离,一个进程中的代码无法更改正在由另一进程使用的物理内存
      3. 方便OS使用你那可怜的内存

        1. 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区,当物理内存的供应变小时,内存管理器会将物理内存页(通常大小为4kb)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。
  4. C库函数与系统函数的关系

    1. printf函数->标准输出(stdout):FILE* printf("Hello");

      1. 文件描述符
      2. 文件指针
      3. IO缓冲区
    2. 调用write函数将文件描述符传递过去(系统API)

      1. write(fd, "Hello", 5);
    3. 系统API write函数对用户空间做操作,然后会从用户空间到 内核空间做个转换

      1. 在内核空间有个sys_write()对内核做操作 然后调用设备驱动
    4. 调用设备驱动

      1. 显示器

        1. 把数据写到屏幕上
      2. ......
    5. 读大文件 --- 写到另一个文件

      1. 两种方式,那种效率高?

        1. read write -- 每次读1个byte
        2. getc putc -- 每次读1个byte -- 效率高 因为标准C库函数,内部有一个buff缓冲区

# Linux系统IO函数

    1. man帮助文档(页面)
    2. 1552791352692
      1552791352692
    3. 查看函数使用说明 man 2(页数) open(函数名)
    4. 使用open系统函数,如果失败则会返回错误码

      1. error错误码表(宏函数)

        1. 第1-34个错误定义 /usr/include/asm-generic/errno-base.h
        2. 第35-133个错误定义 /usr/include/asm-generic/errno.h
      2. 使用perror(const char * s)打印错误 需要包含<stdio.h>头文件
    5. open函数

    1.

    int open(const char *pathname, int flags);
    int open(const char *pathname, int flags, mode_t mode);
    1. flags必选项:

      1. O_RDONLY 只读
      2. O_WRONLY 只写
      3. O_RDWR 读写
    2. mode_t mode可选项

      1. O_CREAT

        1. 文件权限:本地有个掩码

          1. 文件实际权限
          2. 本地掩码(取反在做&操作)
          3. 实际的文件的权限
          4. 777 111111111 掩码0022(10110)
          5. 111111111
          6. 00001001
          7. 00001001
      2. O_EXCL

        1. 判断文件是否存在 需要和O_CREAT一起使用
      3. O_TRUNC

        1. 截断文件为0 不需要和O_CREAT一起使用
    3. #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <stdio.h>
      #include <unistd.h>
      #include <stdlib.h>
      
      int main()
      {
          int fd;
         /*
          //打开已经存在的文件
          fd = open("bucunz", O_RDWR);
          if(fd == -1)
          {
         perror("open file");
         exit(1);
          }
      
          //创建新文件
          fd = open("hello.c", O_RDWR | O_CREAT, 0777);
          if(fd == -1)
          {
         perror("open file");
         exit(1);
          }
      
          printf("fd = %d\n", fd);
      
          //判断文件是否存在
          fd = open("myhello", O_RDWR | O_CREAT | O_EXCL, 0777);
          if(fd == -1)
          {
         perror("open file");
         exit(1);
          }
      */
          //将文件截断为0
          fd = open("myhello", O_RDWR | O_TRUNC);
          if(fd == -1)
          {
         perror("open file");
         exit(1);
          }
      
          //关闭文件
          int ret = close(fd);
      
          printf("ret = %d\n", ret);
          if(ret == -1)
          {
         perror("close file");
         exit(1);
          }
          return 0;
      }
    1. read函数

      1. #include <unistd.h>
        ssize_t read(int fd, void *buf, size_t count);
      2. ssize_t有符号的int size_t无符号的int
      3. 参数

        1. fd 文件描述符
        2. buf 缓冲区
        3. count 读数据的buff多大
      4. 返回值ssize_t 因为需要-1

        1. -1 读取文件失败
        2. 0 文件读完了
        3. 大于0的数读取字节数
    2. write函数

      1. #include <unistd.h>
        ssize_t write(int fd, const void *buf, size_t count);
      2. 参数

        1. fd 文件描述符
        2. buff缓冲区
        3. count 写数据的buff大小
      3. 返回值是ssize_t 因为需要-1

        1. -1 写入文件失败
        2. 0 文件写完了
        3. 大于0的数读写入字节数
    3. read_write

      1. #include <stdlib.h>
        #include <stdio.h>
        #include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        #include <unistd.h>
        
        int main()
        {
            //打开一个已经存在的文件
            int fd = open("english.txt", O_RDONLY);
            if(fd == -1)
            {
                perror("open");
                exit(1);
            }
        
            //创建一个新文件 ——写操作
            int fd1 = open("newfile", O_CREAT | O_WRONLY, 0664);
            if(fd1 == -1)
            {
                perror("open1");
                exit(1);
            }
        
            //read file
            char buf[2048] = {0};
            int count = read(fd, buf, sizeof(buf));
            if(count == -1)
            {
                perror("read");
                exit(1);
            }
        
            while(count)
            {
                //将读出的数据写入另一个文件中
                int ret = write(fd1, buf, count);
                printf("write bytes %d\n", ret);
        
                //continue read file
                count = read(fd, buf, sizeof(buf));
            }
        
            //close file
            close(fd);
            close(fd1);
        
            return 0;
        }
    4. lseek函数

      1. #include <sys/types.h>
        #include <unistd.h>
        off_t lseek(int fd, off_t offset, int whence);
      2. 参数

        1. fd 文件描述符
        2. off_t offset文件指针偏移量
        3. whence 在什么位置偏移 {SEEK_SET开始位置/SEEK_CUR当前位置/SEEK_END结束位置}

    3.

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main()
    {
        int fd = open("aa", O_RDWR);
        if(fd == -1)
        {
            perror("open file");
            exit(1);
        }
        int ret = lseek(fd, 0, SEEK_END);
        printf("file length = %d\n", ret);
    
        // 文件拓展
        ret = lseek(fd, 2000, SEEK_END);
        printf("return value %d \n", ret);
        //实现文件拓展,需要在最后做一次写操作
        write(fd, "a", 1);
        close(fd);
        return 0;
    }

    # Linux文件操作相关函数

    1. stat

      1. stat命令

        1. 1552798919037
          1552798919037
      2. stat函数

        1. #include <sys/types.h>
          #include <sys/stat.h>
          #include <unistd.h>
          int stat(const char *path, struct stat *buf);
        2. 参数

          1. path 文件路径
          2. buf 传出参数 他会把数据写到这个buf传出
        3. 穿透(追踪)函数 -- 软链接

          1. 1552799171749
            1552799171749
          2. 1552799234673
            1552799234673
        4. #include <sys/types.h>
          #include <sys/stat.h>
          #include <stdlib.h>
          #include <time.h>
          #include <pwd.h>
          #include <grp.h>
          #include <stdio.h>
          #include <string.h>
          
          int main(int argc, char * argv[])
          {
               if(argc < 2)
               {
                   printf("./a.out filename\n");
                   exit(1);
               }
          
               struct stat st;
               int ret = stat(argv[1], &st);
               if(ret == -1)
               {
                   perror("stat");
                   exit(1);
               }
          
               //存储文件类型和访问权限
               char perms[11] = {0};
               //判断文件类型
               switch(st.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';
                   case S_IFIFO:
                       perms[0] = 'P';
                       break;
                   default:
                       perms[0] = '?';
                       break;
               }
          
               //判断文件的访问权限
               //文件所有者
               perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
               perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
               perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
               //文件所属组
               perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
               perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
               perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
               //其他人
               perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
               perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
               perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';
          
               //硬链接数
               int linkNum = st.st_nlink;
               //文件所有者
               char* fileUser = getpwuid(st.st_uid)->pw_name;
               //文件所属组
               char * fileGrp = getgrgid(st.st_gid)->gr_name;
               //文件大小
               int fileSize = (int)st.st_size;
               //修改时间
               char * time = ctime(&st.st_mtime);
               char mtime[512] = {0};
               strncpy(mtime, time, strlen(time)-1);
          
               char buf[1024];
               sprintf(buf, "%s    %d  %s  %s  %d  %s  %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);
               printf("%s\n", buf);
               return 0;
          }
        5. lstat

          1. #include <sys/types.h>
            #include <sys/stat.h>
            #include <unistd.h>
            int lstat(const char *path, struct stat *buf);
          2. 参数

            1. path 文件路径
            2. buf 传出参数 他会把数据写到这个buf传出
          3. 不穿透(不追踪)--符号链接 ls -l rm

        4.

        #include <sys/types.h>
        #include <sys/stat.h>
        #include <stdlib.h>
        #include <time.h>
        #include <pwd.h>
        #include <grp.h>
        #include <stdio.h>
        #include <string.h>
        
        int main(int argc, char * argv[])
        {
             if(argc < 2)
             {
                 printf("./a.out filename\n");
                 exit(1);
             }
        
             struct stat st;
             int ret = lstat(argv[1], &st);
             if(ret == -1)
             {
                 perror("stat");
                 exit(1);
             }
        
             //存储文件类型和访问权限
             char perms[11] = {0};
             //判断文件类型
             switch(st.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';
                 case S_IFIFO:
                     perms[0] = 'P';
                     break;
                 default:
                     perms[0] = '?';
                     break;
             }
        
             //判断文件的访问权限
             //文件所有者
             perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
             perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
             perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
             //文件所属组
             perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
             perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
             perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
             //其他人
             perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
             perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
             perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';
        
             //硬链接数
             int linkNum = st.st_nlink;
             //文件所有者
             char* fileUser = getpwuid(st.st_uid)->pw_name;
             //文件所属组
             char * fileGrp = getgrgid(st.st_gid)->gr_name;
             //文件大小
             int fileSize = (int)st.st_size;
             //修改时间
             char * time = ctime(&st.st_mtime);
             char mtime[512] = {0};
             strncpy(mtime, time, strlen(time)-1);
        
             char buf[1024];
             sprintf(buf, "%s    %d  %s  %s  %d  %s  %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);
             printf("%s\n", buf);
             return 0;
        }
    2. access函数

      1. 测试指定文件是否有某种权限
      2. #include <unistd.h>
        int access(const char *pathname, int mode);
      3. 参数

        1. pathname 文件名
        2. mode 权限类别

          1. R_OK 是否有读权限
          2. W_OK 是否有写权限
          3. X_OK 是否有执行权限
          4. F_OK 测试一个文件是否存在
      4. 返回值

        1. 0 所有欲查核权限都通过了检查
        2. -1 有权限被禁止了
      5. #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        
        int main(int argc, char* argv[])
        {
          if(argc < 2)
          {
              printf("a.out filename\n");
              exit(1);
          }
        
          int ret = access(argv[1], W_OK);
          if(ret == -1)
          {
              perror("access");
              exit(1);
          }
          printf("you can write this file.\n");
          return 0;
        }
    3. chmod函数

      1. 改变文件权限
      2. #include <sys/stat.h>
        int chmod(const char *path, mode_t mode);
        int fchmod(int fd, mode_t mode);
      3. path 文件路径
      4. mode 文件权限 必须是八进制数
      5. 返回值

        1. 0 成功
        2. -1 失败
      6. #include <stdio.h>
        #include <sys/stat.h>
        #include <stdlib.h>
        
        int main(int argc, char* argv[])
        {
          if(argc < 2)
          {
              printf("a.out filename\n");
              exit(1);
          }
        
          int ret = chmod(argv[1], 0775);
          if(ret == -1)
          {
              perror("chmod");
              exit(1);
          }
          return 0;
        }
    4. chown函数

      1. 改变所有者
      2. #include <unistd.h>
        int chown(const char *path, uid_t owner, gid_t group);
        int fchown(int fd, uid_t owner, gid_t group);
        int lchown(const char *path, uid_t owner, gid_t group);
      3. path 文件路径
      4. owner 所有者
      5. group 所属组

      6.

      #include <stdio.h>
      #include <stdlib.h>
      #include <unistd.h>
      
      int main(int argc, char* argv[])
      {
          if(argc < 2)
          {
              printf("a.out filename!\n");
              exit(1);
          }
      
          int ret = chown(argv[1], 110, 110);
          if(ret == -1)
          {
              perror("chown");
              exit(-1);
          }
          return 0;
      }
    5. truncate函数

      1. 将参数path指定的文件大小为参数length指定的带下。如果原来的文件大小比参数length大,则超出部分被删除
      2. #include <unistd.h>
        #include <sys/types.h>
        
        int truncate(const char *path, off_t length);
        int ftruncate(int fd, off_t length);
      3. 参数

        1. path 文件路径
        2. length 指定文件的大小
      4. 返回值

        1. 0 执行成功
        2. 1 执行失败
      5. #include <stdio.h>
        #include <sys/types.h>
        #include <stdlib.h>
        #include <unistd.h>
        
        int main(int argc, char*argv [])
        {
          if(argc < 2)
          {
              printf("./a.out filename!\n");
              exit(1);
          }
        
          int ret = truncate(argv[1], 100);
          if(ret == -1)
          {
              perror("truncate");
              exit(1);
          }
          return 0;
        }
    6. link

      1. link函数

        1. 创建一个硬链接
        2. #include <unistd.h>
          int link(const char *oldpath, const char *newpath);
        3. 参数

          1. oldpath 目标文件
          2. newpath 创建的硬链接名
        4. 返回值

          1. 0 成功
          2. -1 失败
        5. #include <stdio.h>
          #include <unistd.h>
          #include <stdlib.h>
          
          int main(int argc, char* argv[])
          {
              if(argc < 3)
              {
                  printf("./out oldFileName newfileName\n");
                  exit(1);
              }
          
              int ret = link(argv[1], argv[2]);
              if(ret == -1)
              {
                  perror("link");
                  exit(1);
              }
          
              return 0;
          }
      2. symlink函数

        1. 创建一个软链接
        2. #include <unistd.h>
          int symlink(const char *oldpath, const char *newpath);
        3. 参数

          1. oldpath 目标文件
          2. newpath 创建的硬链接名
        4. 返回值

          1. 0 成功
          2. -1 失败
        5. #include <stdio.h>
          #include <unistd.h>
          #include <stdlib.h>
          
          int main(int argc, char* argv[])
          {
              if(argc < 3)
              {
                  printf("./out oldFileName newfileName\n");
                  exit(1);
              }
          
              int ret = symlink(argv[1], argv[2]);
              if(ret == -1)
              {
                  perror("link");
                  exit(1);
              }
          
              return 0;
          }
      3. readlink函数

        1. 读取软连接对应文件名
        2. #include <unistd.h>
          ssize_t readlink(const char *path, char *buf, size_t bufsiz);
        3. 参数

          1. path 文件路径
          2. buf 读出来的软连接名字放入其中
          3. bufsiz 的大小
        4. 返回值

          1. 0成功
          2. -1失败
        5. #include <stdio.h>
          #include <stdlib.h>
          #include <unistd.h>
          
          int main(int argc, char* argv [])
          {
              if(argc < 2)
              {
                  printf("a.out softlink\n");
                  exit(1);
              }
          
              char buf[512];
              int ret = readlink(argv[1], buf, sizeof(buf));
              if(ret == -1)
              {
                  printf("readlink");
                  exit(1);
              }
              buf[ret] = 0;
              printf("buf = %s\n", buf);
              return 0;
          }
      4. unlink函数

        1. 删除一个文件目录项并减少它的链接数
        2. 通过调用这个函数来成功删除文件,你就必须拥有这个文件的所属目录的写和执行权限
        3. #include <unistd.h>
          int unlink(const char *pathname);
        4. 参数

          1. pathname 文件名
        5. 返回值

          1. 0 成功
          2. -1 失败 错误原因存于error
        6. 使用

          1. 如果是符号链接,删除符号链接
          2. 如果是硬链接,硬链接数减1,当减为0时,释放数据块和inode
          3. 如果文件硬链接数为0,但又进程已经打开文件,并持有文件描述符,则等该进程关闭该文件时,kernel才真正去删除该文件

            1. 利用该特性创建临时文件,先open或create文件,然后unlink掉文件,进程文件临时则不存在,比如在看一段视频产生的临时文件就可以用这种方法操作,看完关闭视频软件,临时文件就被kernel删除
        7. #include <stdio.h>
          #include <stdlib.h>
          #include <sys/types.h>
          #include <unistd.h>
          #include <sys/types.h>
          #include <sys/stat.h>
          #include <fcntl.h>
          
          int main()
          {
              int fd = open("tempfile",  O_CREAT | O_RDWR, 0664);
              if(fd == -1)
              {
                  perror("open");
                  exit(1);
              }
          
              //删除临时file
              int ret = unlink("tempfile");
          
              //write file
              write(fd, "hello", 5);
          
              //重置文件指针
              lseek(fd, 0, SEEK_SET);
          
              //read file
              char buf[24] = {0};
              int len = read(fd, buf, sizeof(buf));
          
              //将读出的内容,写到屏幕上
              write(1, buf, len);
          
              //close file
              close(fd);
              return 0;
          }
    7. rename函数

      1. 文件重命名

      2.

      #include <stdio.h>
      int rename(const char *oldpath, const char *newpath);
      1. 参数

        1. oldpath 老的文件名
        2. newpath 新的文件名
      2. 返回值

        1. 0 成功
        2. -1 失败
      3. #include <stdio.h>
        #include <stdlib.h>
        
        int main(int argc, char* argv[])
        {
          if(argc < 3)
          {
              printf("./a.out oldPath newPath");
              exit(1);
          }
        
          int ret = rename(argv[1], argv[2]);
          if(ret == -1)
          {
              perror("rename");
              exit(-1);
          }
          return 0;
        }

    Linux目录操作相关函数

    1. chdir函数

      1. 修改当前进程路径
      2. #include <unistd.h>
        int chdir(const char *path);
        int fchdir(int fd);
      3. 参数

        1. path 当前要改变的工作目录
      4. 返回值

        1. 0 成功
        2. -1 失败
      5. #include <stdio.h>
        #include <stdlib.h>
        #include <sys/types.h>
        #include <fcntl.h>
        #include <sys/stat.h>
        #include <unistd.h>
        
        int main(int argc, char* argv[])
        {
           if(argc < 2)
           {
               printf("a.out dit\n");
               exit(1);
           }
        
           int ret = chdir(argv[1]);
           if(ret == -1)
           {
               perror("chdir");
               exit(1);
           }
        
           int fd = open("chdir.txt", O_CREAT | O_RDWR, 0777);
           if(fd == -1)
           {
               perror("open");
               exit(1);
           }
           close(fd);
        
           char buf[128];
           getcwd(buf, sizeof(buf));
           printf("current dir: %s\n", buf);
           return 0;
        }
    2. getpwd函数

      1. 获取当前路径

    2.

     #include <unistd.h>
     char *getcwd(char *buf, size_t size);
     char *getwd(char *buf);
     char *get_current_dir_name(void);
    1. 参数

      1. buf 获取到的路径信息写到该buf中
      2. buf的大小

    4.

     #include <stdio.h>
     #include <unistd.h>
     
     int main()
     {
         char buf[128];
         getcwd(buf, sizeof(buf));
         printf("curretn dir: %s\n", buf);
         return 0;
     }
    1. mkdir函数

      1. 创建目录

        1. 创建目录需要有执行权限,否则无法进入目录
      2. #include <sys/stat.h>
        #include <sys/types.h>
        int mkdir(const char *pathname, mode_t mode);
      3. 参数

        1. pathname 要创建的目录路径名
        2. mode 目录的权限
      4. 返回值

        1. 0 成功
        2. -1 失败
      5. #include <stdio.h>
        #include <sys/stat.h>
        #include <sys/types.h>
        #include <stdlib.h>
        
        int main(int argc, char* argv[])
        {
           if(argc < 2)
           {
               printf("./a.out create new dirName");
               exit(1);
           }
        
           int ret = mkdir(argv[1], 0665);
           if(ret == -1)
           {
               perror("mkdir");
               exit(1);
           }
           return 0;
        }
    2. rmdir函数

      1. 删除一个空目录
      2. #include <unistd.h>
        int rmdir(const char *pathname);
      3. 参数

        1. pathname 要删除的文件夹路径名
      4. 返回值

        1. 0 成功
        2. -1 失败

    5.

     #include <stdio.h>
     #include <unistd.h>
     #include <stdlib.h>
     
     int main(int argc, char* argv[])
     {
         if(argc < 2)
         {
             printf("./a.out remove pathDirName");
         }
     
         int ret = rmdir(argv[1]);
         if(ret == -1)
         {
             perror("rmdir");
             exit(1);
         }
         return 0;
     }
    1. man 帮助文档第3页
    2. opendir函数

      1. 打开一个目录
      2. #include <sys/types.h>
        #include <dirent.h>
        DIR *opendir(const char *name);
        DIR *fdopendir(int fd);
      3. 参数

        1. name 文件目录路径
      4. 返回值DIR *

        1. 成功 DIR目录指针
        2. 失败 NULL
    3. readdir函数

      1. 读取目录

    2.

     #include <dirent.h>
     struct dirent *readdir(DIR *dirp);
     int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
    1. 返回值 struct dirent *

    1. closedir函数

      1. 关闭目录
      2. #include <sys/types.h>
        #include <dirent.h>
        int closedir(DIR *dirp);
      3. 返回值

        1. 0 成功
        2. -1 失败
    2. 递归读目录,获取文件个数(运用opendir/readdir/closedir函数)

      1. #include <stdio.h>
        #include <sys/types.h>
        #include <dirent.h>
        #include <stdlib.h>
        #include <string.h>
        
        int getFileNum(char * root)
        {
           //open dir
           DIR* dir = NULL;
           dir = opendir(root);
           if(dir == NULL)
           {
               perror("opendir");
               exit(1);
           }
        
           //遍历当前打开的目录
           struct dirent* ptr = NULL;
           char path[1024] = {0};
           int total = 0;
           while((ptr = readdir(dir)) != NULL)
           {
               //过滤. 和..
               if(strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
                   continue;
        
               //如果是目录
               if(ptr->d_type == DT_DIR)
               {
                   //递归读目录
                   sprintf(path, "%s/%s", root, ptr->d_name);
                   total += getFileNum(path);
               }
        
               //如果时普通文件
               if(ptr->d_type == DT_REG)
                   total++;
           }
        
           closedir(dir);
           return total;
        }
        
        int main(int argc, char* argv[])
        {
           if(argc < 2)
           {
               printf("./a.out dir\n");
               exit(1);
           }
           int total = getFileNum(argv[1]);
           printf("%s has file numbers %d\n", argv[1], total);
           return 0;
        }
    3. dup函数

      1. 拷贝文件描述符表
      2. #include <unistd.h>
        int dup(int oldfd);
      3. 参数

        1. oldfd 老的文件描述符
      4. 返回值

        1. 成功返回文件描述符表中没有被占用的最小文件描述符
        2. 失败返回-1

      5.

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <unistd.h>
        #include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        
        int main()
        {
            int fd = open("a.txt", O_RDWR);
            if(fd == -1)
            {
                perror("open");
                exit(1);
            }
        
            printf("file open fd = %d\n", fd);
        
            //找到进程文件描述符表 第一个 可用的文件描述符
            //将参数指定的文件复制到该描述符后,返回这个二描述符
            int ret = dup(fd);
            if(ret == -1)
            {
                perror("dup");
                exit(1);
            }
        
            printf("dup fd = %d\n", ret);
            char * buf = "你是猴子派来的救兵吗??\n";
            char * buf1 = "你大爷的,我是程序猿!\n";
            write(fd, buf, strlen(buf));
            write(ret, buf1, strlen(buf1));
        
            close(fd);
            return 0;
        }
    4. dup2函数

      1. 把旧的描述符复制给新的描述符

        #include <unistd.h>
        int dup2(int oldfd, int newfd);
      2. 参数

        1. oldfd 旧的文件描述符
        2. newfd 新的文件描述符
      3. 返回值

        1. 成功返回新的描述符

          1. 把老的描述符拷贝给新的描述符时,新的描述符如果时打开的,拷贝前先关闭新的描述符,在拷贝,然后指向同一个文件
          2. old和new时同一个文件描述符,则不会关闭文件描述符,返回old的描述符
        2. 失败返回-1

      4.

          #include <stdio.h>
          #include <sys/types.h>
          #include <sys/stat.h>
          #include <fcntl.h>
          #include <stdlib.h>
          #include <unistd.h>
          #include <string.h>
          
          int main()
          {
        int fd = open("english.txt", O_RDWR);
        if(fd == -1)
        {
            perror("open");
            exit(1);
        }
          
        int fd1 = open("a.txt", O_RDWR);
        if(fd1 == -1)
        {
            perror("open");
            exit(1);
        }
          
        printf("fd = %d\n", fd);
        printf("fd1 = %d\n", fd1);
          
        int ret = dup2(fd1, fd);
        if(ret == -1)
        {
            perror("dup2");
            exit(1);
        }
        printf("current fd = %d\n", ret);
        char* buf = "主要看气质!\n";
        write(fd, buf, strlen(buf));
        write(fd1, "hello world", 13);
          
        close(fd);
        close(fd1);
        return 0;
          }
    5. fcntl函数

      1. 改变已经打开的文件属性

        1. 打开文件的时候 只读 我想在后面追加一些内容
        2. 这个时候就可以改变文件属性,不需要关闭文件在给它权限,再打开文件, 现在可以直接可以添加追加 O_APPEND权限
      2. #include <unistd.h>
        #include <fcntl.h>
        int fcntl(int fd, int cmd, ... /* arg */ );
      3. 参数

        1. fd 文件描述符
        2. cmd 设置获取↓

          1. 如果是获取返回值则是对应的状态 arg填0
        3. arg 可变参
      4. 其他作用

        1. 复制一个现有的描述符 cmd

          1. F_DUPFD
        2. 获得/设置文件描述符标记 cmd

          1. F_GETFD
          2. F_SETFD
        3. 获得/设置文件状态标记 cmd

          1. F_GETFL

            1. 只读打开 O_RDONLY
            2. 只写打开 O_WRONLY
            3. 读写打开 O_RDWR
            4. 执行打开 O_EXEC
            5. 搜索打开目录 O_SEARCH
            6. 追加写 O_APPEND
            7. 非阻塞模式 O_NONBLOCK
          2. F_SETFL

            1. 可更改的几个标识

              1. O_APPEND
              2. O_NONBLOCK
        4. 获得/设置异步IO所有权cmd

          1. F_GETOWN
          2. F_SETOWN
        5. 获得/设置记录锁 cmd

          1. F_GETLK
          2. F_SETLK
          3. F_SETLKW
      5. #include <stdio.h>
        #include <stdlib.h>
        #include <fcntl.h>
        #include <unistd.h>
        #include <string.h>
        
        int main()
        {
           int fd;
           int flag;
        
           //测试字符串
           char *p = "china No.1";
           char *q = "6666666";
        
           //只写的方式打开文件
           fd = open("test.txt", O_WRONLY);
           if(fd == -1)
           {
               perror("open");
               exit(1);
           }
        
           //输入新的内容, 该部分会覆盖原来旧的内容
           if(write(fd, p, strlen(p)) == -1)
           {
               perror("write");
               exit(1);
           }
        
           //使用 F_GETFL 命令得到文件的状态标志
           flag = fcntl(fd, F_GETFL, 0);
           if(flag == -1)
           {
               perror("fcntl");
               exit(1);
           }
        
           //将文件状态标志添加“追加写”选项
           flag |= O_APPEND;
           //将文件状态修改为追加写
           if(fcntl(fd, F_SETFL, flag) == -1)
           {
               perror("fcntl -- append write");
               exit(1);
           }
        
           //再次输入新的内容,该内容会追加到旧内容的后面
           if(write(fd, q, strlen(q)) == -1)
           {
               perror("write again");
               exit(1);
           }
        
           //关闭文件
           close(fd);
           return 0;
        }