Linux 操作一:系统调用:文件读写

Linux 操作一:系统调用:文件读写

基本概念

  • 什么是文件

​ 简单的说,文件就是存储在硬件磁盘上的数据集合。

  • 文件通过什么来标识

​ 系统中在处理的文件(读、写操作)的时候,需要唯一能够识别这个文件,就需要一个针对文件的标识,以便在其它地方能识别出这个文件,于是就产生了文件描述符。

  • 文件描述符

​ 文件描述符是一些整数,简单的说就是一个文件ID,用于在系统中唯一的标识一个文件。文件描述符的总数也就是系统可以打开文件的最多个数,这取决于系统的配置情况。可打开的文件描述符总数可利用cat /proc/sys/fs/file-max 来查看。程序在运行初,系统会默认打开3个文件描述符,分别为 标准输入,输出,错误文件描述符,在中有以下定义:

#define STDIN_FILENO 0 // 标准输入设备文件描述符

#define STDOUT_FILENO 1 // 标准输出设备文件描述符

#define STDERR_FILENO 2 // 标准错误设备文件描述符

  • **文件类型: **

​ 普通文件(-);目录文件(d);链接文件(l);字符设备文件(c);块设备文件(b) 管道文件(p) 套接字文件(s)

  • 访问权限:

​ 读权限(r);写权限(w);可执行权限(x)

  • Linux文件特点:

    • 可通过操作系统或者程序对外提供信息,也能对内输入信息,可以被创建,删除;

    • 为操作系统和设备提供了一个简单而统一的接口。

    • 普通程序完全可以像使用文件(普通定义)那样使用磁盘文件、串行口、打印机和其他设备;

    • 硬件设备在linux操作系统中也被表示为文件。

系统调用

​ 系统调用,由操作系统直接提供,他们是通向操作系统(内核)本身的接口,针对文件操作来说,系统调用是最直接的方式。

常用函数
  1. int access(const char *path, int mode);确定文件或文件夹是否存在,访问权限
  2. int open(const char *path, int oflags);
  3. int open(const char *path, int oflags, mode_t mode );
  • ssize_t read(int fd, void *buf, size_t count);
  • ssize_t write(int fd, const void *buf, size_t count);
  1. int close(int fd);
  2. off_t lseek(int fd, off_t offset, int whence);
  3. int stat(const char filename, struct stat buf);

判断文件或文件夹是否存在

  • 头文件

    #include    
    #include 
    
  • 函数原型

    int access(const char *path, int mode);
    
  • 参数说明

    • pathname:要操作的文件名或路径,也可以是目录名;

      注意:如果Pathname 为目录名,则mode 只能取值 F_OK,用来判断目录是否存在;

    • mode :判断模式,可取值如下:

      • R_OK:判断文件是否有读权限
      • W_OK :判断文件是否有写权限
      • X_OK:判断文件是否有执行权限
      • F_OK:判断文件是否存在
  • 返回值

    如果指定的mode 方式有效,返回0,否则返回-1, 错误码放在errno

  • 实例:

    #include 
    #include 
    #include 
    
    int main(int argc,char *argv[])
    {
        //是否存在
        int r1=access(".",F_OK);
        //读权限
        int r2=access(".",R_OK);
        //写权限
        int r3=access(".",W_OK);
        //执行权限
        int r4=access(".",X_OK);
        printf("%d%d%d%d\n",r1,r2,r3,r4);
        return 0;
    }
    

打开文件

  • 头文件

    #include    
    #include 
    
  • 函数原型

    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: 读写

        附加选项:O_APPEND:在写入文件时将数据追加到文件的末尾

        ​ O_CREAT:当打开的文件不存在时,创建该文件

        ​ O_TRUNC:截断文件,即如果文件已经存在,在打开时将文件的内容清空

    • mode:如果以新建方式打开文件,这个参数用于设置文件的访问权限

    S_IRWXU 00700 文件拥有者可读,可写,可执行

    S_IRUSR 00400 文件拥有者可读

    S_IWUSR 00200 文件拥有者可写

    S_IXUSR 00100 文件拥有者可执行

    S_IRWXG 00070 组用户可读,可写,可执行

    S_IRGRP 00040 组用户可读

    S_IWGRP 00020 组用户可写

    S_IXGRP 00010 组用户可执行

    S_IRWXO 00007 其他组用户可读,可写,可执行

    S_IROTH 00004 其他组用户可读

    S_IWOTH 00002 其他组用户可写

    S_IXOTH 00001 其他组用户可执行

    • 返回值

      如果成功,返回文件描述符,否则返回-1,错误码放在errno

关闭文件

  • 头文件

    #include    
    #include 
    
  • 函数原型

    int close(int fd)
    
  • 参数说明

    fd:要操作的文件描述符;

  • 返回值

    成功,返回0,失败返回-1,并将错误码放入 errno

读文件

  • 头文件

    #include    
    #include 
    
  • 函数原型

    ssize_t read(int fd, void *buf, size_t count);
    
  • 参数说明

    • fd:要操作的文件描述符;

    • buf:数据缓冲区,用来临时存放读取到的数据:

    • count:设置要读取的字节数

  • 返回值

    • 成功:返回实际读取到的字节数

    • 0 :到达文件尾部,或没有可读的数据

    • 出错:返回 -1,并将错误码存入 errno 中

写文件

  • 头文件

    #include    
    #include 
    
  • 函数原型

    ssize_t write(int fd, const void *buf, size_t count)
  • 参数说明

    • fd:要操作的文件描述符;

    • buf:数据缓冲区,临时存放要写入的数据:

    • count:要写入的字节数

  • 返回值

    • 成功:返回实际写入到文件的字节数
    • 出错:返回 -1,并将错误码存入 errno 中

文件指针移动

  • 头文件

    #include    
    #include 
    
  • 函数原型

    off_t lseek(int fd, off_t offset, int whence)
    
  • 参数说明

    • fd:要操作的文件描述符;

    • offset:相对于whence 的偏移量:

    • whence:移动方式,可取以下值:

      • SEEK_SET: 文件头部

      • SEEK_CUR: 当前位置

      • SEEK_END: 文件末尾

  • 返回值

    • 成功:返回文件指针的偏移量

    • 出错:返回 -1,并将错误码存入 errno 中

  • 实例

    c
    #include 
    #include 
    #include 
    
    int main() {
        // 打开文件 example.txt 进行读写
        int fd = open("example.txt", O_RDWR);
        if (fd == -1) {
            perror("Error opening file");
            return -1;
        }
    
        // 将文件指针移动到文件开头
        off_t new_offset = lseek(fd, 0, SEEK_SET);
        if (new_offset == -1) {
            perror("Error beginning ");
            close(fd);
            return -1;
        }
        printf("文件指针移动到文件开头.\n");
    
        // 将文件指针移动到文件末尾
        new_offset = lseek(fd, 0, SEEK_END);
        if (new_offset == -1) {
            perror("Error end");
            close(fd);
            return -1;
        }
        printf("将文件指针移动到文件末尾: %ld\n", new_offset);
    
        // 将文件指针向前移动100个字节
        new_offset = lseek(fd, -100, SEEK_END);
        if (new_offset == -1) {
            perror("Error end 100");
            close(fd);
            return -1;
        }
        printf("将文件指针向前移动100个字节\n");
    
        close(fd);
        return 0;
    }
    

在C语言中,我们学习了标准I/O,也可以实现文件的读写,那与我们今天所说的系统调用有什么区别呢?

系统调用 库函数 (标准I/O)
所需头文件 #include 、 #include #include
函数 open,close,read,write,lseek fopen,fclose,fread,fwrite,fseek
函数返回值 lseek 会返回文件读取位置 fseek 不会返回,必须要用 ftell 来获取
文件标识 文件描述符 FILE* 文件流指针
系统效率
总结
  • 标准I/O 是操作系统和应用程序之间的高层接口,提供了更简洁的文件操作方法,适合常见的应用。
  • 系统调用 是与操作系统内核直接交互的低层接口,提供了更大的灵活性和控制,但也需要更多的编程技巧,适合对性能有较高要求或需要精确控制的场合。

k 不会返回,必须要用 ftell 来获取 |
| 文件标识 | 文件描述符 | FILE* 文件流指针 |
| 系统效率 | 低 | 高 |

总结
  • 标准I/O 是操作系统和应用程序之间的高层接口,提供了更简洁的文件操作方法,适合常见的应用。
  • 系统调用 是与操作系统内核直接交互的低层接口,提供了更大的灵活性和控制,但也需要更多的编程技巧,适合对性能有较高要求或需要精确控制的场合。

你可能感兴趣的:(linux,服务器)