Linux 基础 I/O

Linux 基础 I/O

概念

在 Linux 操作系统中,实现了两类对文件 I/O 的管理,一类遵循 POSIX 标准,Linux 操作系统自身提供的 IO 系统调用函数,直接进行 IO 系统调用,我们在这里对这些函数进行简单的介绍。

特性

  • 系统调用的 I/O 函数是不带缓冲的 I/O。每个 read 和 write 都调用内核中的一个系统调用。
  • 所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核返回一个唯一的文件描述符。
  • 系统把文件描述符 0 与进程的标准输入相关联,文件描述符 1 与标准输出相关联,文件描述符 2 与标准错误相关联。

函数

打开/创建文件

open 函数

int open(const char* filename, // 想要打开/创建的文件的路径
                     int flag, // 打开文件的方式
                     /*
                     O_RDONLY 只读方式打开
                     O_WRONLY 只写方式打开
                     O_RDWR   可读可写方式打开
                     以上三种打开方式同时只能存在一种
                     O_CREAT  若要打开的文件不存在则自动创建
                     O_EXCL   如果打开的文件存在/为符号链接则报错
                     O_EXCL   通常与 O_CREAT 一起搭配使用
                     O_TRUNC  文件截断
                     其他的参数可以自己查找 man 手册
                     */
                         ...)  // 创建时需要的第三个参数,用来约定文件权限可以采用直接设置八进制的方式 如 :0644

在这里先只验证 O_CREAT 与 O_EXCL 和 O_TRUNC
O_CREAT
这里写图片描述
这里写图片描述
O_EXCL
由于之前的 test.txt 文件已经创建,此时应该报错。
这里写图片描述
这里写图片描述
O_TRUNC
我们先随便往之前的 test.txt 文件中写一些字符,随后调用 O_TRUNC。
调用前
这里写图片描述
调用后
这里写图片描述
可以发现文件已经被截断。

关闭文件

colse 函数

int close (int fd)
此函数的参数为调用 open 函数打开文件时返回的文件描述符。与 open 搭配使用。

读取文件

read 函数

ssize_t read(int fd, void * buf, size_t count)
在读取数据过程中,文件的读位置会随读取到的字节移动,成功调用返回读取的字节数。
当出现 : 文件中剩余字数小于 count 时
         read 请求已被某个信号中断
         文件是管道文件时
    返回值可能小于欲读取的数据量。

我们先向 test.txt 中加入一些数据。
这里写图片描述
可以看出 test.txt 文件里有 14 个字符。
这里写图片描述
我们给出的 buf 是20个字节的,但是文件中只有 14 个字符,所以 read 函数的返回值应该是等于14 而不是 20的。
这里写图片描述

写入文件

write 函数

ssize_t write(int fd, void *buf, size_t count)
以 buf 为起始地址的缓冲区前 count 个字节写入与打开文件描述符 fd 关联的文件内。
调用成功返回真正写入数据的大小。

因为之前的 test.txt 文件的内容是 abcdefghijklmn 我们从 d 开始插入。要想从 d 的位置开始插入,我们需要将写的位置后移三个字符,在这里我们需要用到 lseek 函数。

off_t lseek(int fd,   // open 函数所返回的文件描述符
            off_t offset,  // 相对于第三个参数的偏移量
            int whence)  // SEEK_SET  0   文件头部
                         // SEEK_CUR  1   当前位置
                         // SEEK_END  2   文件末尾

这里写图片描述
这里写图片描述
可以发现,在添加之后,并不会覆盖后面的内容。
首先我们要清楚 Linux 中的文件结构。
Linux 为管理每个进程打开的文件,在进程的私有结构体 task_struct 中。对任何进程,都将为其专门分配管理打开文件信息的表项,用以指示当前进程打开的文件结构体 struct file,在 struct file 中,将最终指向对应的文件。

struct file{
    struct list_head            f_list;     // 文件对象链表 
    struct dentry               *f_dentry;  // 文件的 dentry 结构
    struct vfsmount             *f_vfsmnt;  // 文件系统挂载信息(所挂载的根目录)
    struct file_openerations    *f_op;      // 文件操作 open read write等
    atomic_t                    f_count;    // 文件的引用计数(有多少个进程打开该文件) 
    unsigned int                f_flags;    // 文件标志也就是 open 函数返回的 fd
    mode_t                      f_mode;     // 文件的打开模式(权限)
    int                         f_error;
    loff_t                      f_pos;      // 文件操作指针的当前位置
    unsigned int                f_uid, f_gid; // 文件的 uid gid
    ...
};

文件描述符 fd :
任何进程在运行时默认打开三个流对象,stdin, stdout, stderr,其文件描述符分别为 0 1 2,以后打开的文件描述符的值一般选用未使用的最小值。
对于用户来说,任何打开的文件都将被分配一个唯一的非负整数,这个整数就是所谓的文件描述符 fd。
在这里我们需要先画出 Linux 文件表图
这里写图片描述
一个进程拥有一个 task_struct 结构体来标识基本信息,其成员 file 指向打开的文件列表,在文件列表中,列出当前进程打开的所有文件,由其成员指向打开的文件信息位置 file 结构体,在 file 结构体中,通过 v 节点最终查找到文件的磁盘位置。

我们可以看到在 file 结构体中有一个 f_pos 的成员,当我们对文件进行读写操作的时候,该成员会随着函数的调用而改变,从而记录文件操作的当前位置,应为每个进程都有会其唯一的 task_struct 结构体来标识信息,所以当多个进程同时进程读操作是不会互相影响的,但是当多个进程同时进行写操作则会出现一些错误现象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值