简 述: 讲解在 Unix / Linux 下,man 手册的使用;写了一个例子调用系统库函数来读写文本文件,和打印文件描述符;阻塞和非阻塞实际是文件的属性,而非标准输入输出的 I/O 函数的属性。 以及文件详细描述的 stat 命令和 stat() 函数的使用;文件属性相关的操作;文件夹遍历和创建、删除的相关函数,可能 Linux 有时候会调用到他们,现在实际上,更多的使用 Qt 的库来对文件进行读写操作;以及关于复制文件描述符的函数 dup() 函数的讲解

[TOC]


本文初发于 “偕臧的小站“,同步转载于此。


编程环境:

  💻: uos20 📎 gcc/g++ 8.3 📎 gdb8.0

  💻: MacOS 10.14 📎 gcc/g++ 9.2 📎 gdb8.3


man 手册的使用:

  • man 2 open 在第二章里面,精确查找 open 函数

  • man man 查看 man 手册的大致介绍 (Linux 下)

  • mac 下安装中文 man 文档:Mac配置中文 man 手册


系统函数读写文件:

如下为 Unix / Linux系统的库函数:

  • open() :打开文件

  • read() :对文件进行读操作

  • write() :对文件进行写操作

  • lseek() :移动文件指针;扩展文件大小(移动指针后,要进行一次写操作)

    • 文件指针移动到头部:lseek(fd, 0, SEEK_SET);

    • 文件指针移动到尾部:lseek(fd, 0, SEEK_END);

    • 文件指针移动到当前位置:lseek(fd, 0, SEEK_SUR);

    • 文件大写为 100K, 扩展到 1000K:

      lseek(fd, 1000, SEEK_END);    //文件指针从文件尾部偏移 1000 大小,这部分用^@ 填充占位
      wrire(fd, "a", 1);            //随便写一个什么到文件中,进行一次写操作
  • 全局变量 errno :对于调用系统函数对文件进行读写操作,函数会返回一个错误 int 类型的数值。而 errno 变量就是不同的错误返回值的含义打印出来(字符串),使得人类可以看懂。调用方法: perror("[注释信息: ]");


写一例子:

  • Linux 系统的函数,调用 openprintfread 写一个例子:

  • 编写代码如下:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <errno.h>
    
    int main()
    {
        int fp = open("hello.txt", O_RDWR);
        int fp2 = open("temp.txt", O_WRONLY | O_CREAT, 0777);  //创建文件时候,必须要有权限
        printf("fp = %d\n", fp);
        printf("fp2 = %d\n", fp2);
    
        if (fp == -1)
            perror("[注释信息: ]");  //如果返回错误,会打印人类可读懂的出字符串
    
        char buf[4096];
        int len = read(fp, buf, sizeof(buf));
    
        while (len > 0)
        {
            int ret = write(fp2, buf, len);
            len = read(fp, buf, sizeof(buf));
            printf("ret = %d\n", ret);
        }
    
        close(fp);
        close(fp2);
    
        return 0;
    }
  • 编译:g++-9 main.cpp -o main

  • 运行:其中 fp 便是打开文件 hello.txt 的文件描述符(因为 0、1、2 被 stdin、stdout、stdout 占了,所以最小就是 3);然后当打开第二个文本文件 temp.txt 的时候,其返回的文件描述符自然就是 4。关于文件描述符,详细原理解释可参考 此篇

源码下载: 07_sysfun


阻塞和非阻塞:

终端程序: bash 为前台程序,当执行 a.out 程序时候,bash 就成为了后台程序,a.out 成为了前台程序(代码执行到,等待输入);当键盘输入完成,a.out 成为了后台程序,bash 成为了前台程序。

当输入的长度 大于 buf[10] 中的 10 时候, 多余的部分就会成为后面的命令输入。

将下面的两种,手动敲一遍。

阻塞非阻塞 情况下,是文件的属性,而非标准输入输出的 I/O 函数的属性。

  • 普通文件:hello.cpp

    • 默认是非阻塞
  • 终端设备 /dev/tty (默认是阻塞)

    • 终端
    • 管道
    • 套接字

stat / lstat 函数 :

  • 写一个小的程序,判断 ls -l 命令,基本可以实现 改用 switch()

  • lstatstat 函数对于链接 l 的区别不一样。

    • lstat 读取的是链接文件, 本身的属性
    • stat 读取的是链接文件指向的文件的属性 (也被称呼:追踪,穿透)
    • fstat 第一个参数是指文件描述符

#对应的 stat 命令:

作用:显示文件或文件系统的状态

uinx: stat -x hello.txt

linux: stat hello.txt


运行命令可以看到:hell.txt 文件的所有信息


ls -l hello.txt 查看看的,前面的 -rwxrwxrwx 就是表示下图的 文件类型文件所有者权限文件所属组权限其他人对该文件的权限


  • 其用 含义就是如下:
  • 其在代码里面,用 struct 所表示的为:
st_ mode -- 16位整数
  0-2 bit--其他人权限
      - S_IROTH  00004    读权限
      - S_IWOTH  00002    写权限
      - S_IXOTH  00001    执行权限
      - S_IRIvxO 00007    掩码,过滤 st_mode 中除其他人权限以外的信息
    
  3-5 bit --所属组权限
      -S_IRGRP   00040    读权限
      -S_IWGRP   00020    写权限
      -S_IXGRP   00010    执行权限
      -S_IRWXG   00070    掩码,过滤 st_mode 中除所属组权限以外的信息
  
  6-8 bit --文件所有者权限
      -S_IRUSR   00400    读权限
      -S_IWUSR   00200    写权限
      -S_IXUSR   00100    执行权限
      -S_IRWXU   00700    掩码,过滤 st_mode 中除文件所有者权限以外的信息。
  
  12-15 bit --文件类型
      -S_IFSOCK  0140000  套接字
      -S_IFLNK   0120000  符号链接(软链接)
      -S_IFREG   0100000  普通文件
      -S_IFBLK   0060000  块设备
      -S_IFDIR   0040000  目录
      -S_IFCHR   0020000  字符设备
      -S_IFIFO   0010000  管道
      -S_IFMT0   0017000  掩码,过滤 st_mode 中除文件类型以外的信息
      
  
 // 命令对应的函数 
int stat(const char *path, struct stat *buf);
int Istat(const char *path, struct stat *buf);

文件属性相关的函数:

  • access() 判断传入的文件,所具有的(读、写、执行、是否存)的权限
  • chmod() 修改文件权限
  • chown() 修改文件所有者和所属组
  • truncate() 修改文件大小
  • ^@ 文件空洞, 填充占位符号,实际就是 \0

目录操作相关函数:

目录操作相关函数:

  • rename() 文件重命名
  • chdir() 修改 当前进程(应用程序)的路径;cd
  • getcwd() 获取当前进程的工作目录;pwd
  • mkdir() 创建目录;mkdir
  • rmdir() 删除一个空目录;rm

目录遍历相关函数: 

  • opendir() 打开一个目录
  • readdir() 读目录(进入子目录,需要手动创建递归函数)
  • close() 关闭目录

dup / dup2 / fcntl 函数:

  • dup() 复制文件描述符
  • dup2() 同上,形参不同(也会称为 参数 2:文件描述符的重定向)
  • fcntl() 修改文件的状态标志

下载地址:

https://github.com/xmuli/linuxExample

欢迎 star 和 fork 这个系列的 linux 学习,附学习由浅入深的目录。