前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >文件 IO 与标准 IO

文件 IO 与标准 IO

作者头像
Jasonangel
发布2021-07-07 10:13:59
1.4K0
发布2021-07-07 10:13:59
举报

Linux 应用编程中最基础的知识:文件 I/O(Input、Outout)。

文件 I/O 指的是对文件的输入/输出操作,就是对文件的读写操作;Linux 下一切皆文件,文件作为 Linux 系统设计思想的核心理念,在 Linux 系统下显得尤为重要,所以对文件的 I/O 操作既是基础也是最重要的部分。

一个通用的 IO 模型通常包括打开文件、读写文件、关闭文件这些基本操作,主要涉及到 4 个函数:open()、read()、write()以及 close()。

文件IO

tips:我们在 Linux 系统下,可以通过 man 命令查看某函数的用法和帮助信息以及头文件引用信息。man 命令后面跟着两个参数,数字 1 表示查看 Linux 命令,数字 2 表示查看系统调用函数,数字 3表示查看标准 C 库函数,最后一个参数表示需要查看的系统调用函数名。举例:

代码语言:javascript
复制
man 2 open //查看 open 函数的帮助信息

打开文件

代码语言:javascript
复制
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

在 Linux 内核提供的标准文件 IO 中,主要以文件描述符fd作为操作句柄,去操作文件。调用open函数打开文件后会获得一个文件描述符fd,fd是一个int 类型的数据。一个进程可以打开多个文件,但是在 Linux 系统中,一个进程可以打开的文件数是有限制,我们可以通过 ulimit -n 命令来查看进程可打开的最大文件数,可以自己设置最大值。该最大值默认情况下是 1024。

所以对于一个进程来说,文件描述符是一种有限资源,文件描述符是从 0 开始分配的,譬如说进程中第一个被打开的文件对应的文件描述符是 0、第二个文件是 1、第三个文件是 2、第 4 个文件是 3……以此类推,所以由此可知,文件描述符数字最大值为 1023(0~1023)。每一个被打开的文件在同一个进程中都有一个唯一的文件描述符,不会重复,如果文件被关闭后,它对应的文件描述符将会被释放,那么这个文件描述符将可以再次分配给其它打开的文件、与对应的文件绑定起来。

在程序中,调用 open 函数打开文件的时候,分配的文件描述符一般都是从 3 开始,因为0、1、2 这三个文件描述符已经默认被系统占用了,分别分配给了系统标注输入(0)、标注输出(1)以及标准错误(2)。

写文件

代码语言:javascript
复制
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

读文件

代码语言:javascript
复制
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

关闭文件

代码语言:javascript
复制
#include <unistd.h>

int close(int fd);

标准IO

不仅是 Linux,很多其它的操作系统都实现了标准 I/O 库。标准 I/O 虽然是对文件 I/O 进行了封装,但事实上并不仅仅只是如此,标准 I/O 会处理很多细节,譬如分配 stdio 缓冲区、以优化的块长度执行 I/O 等,这些处理使用户不必担心如何选择使用正确的块长度。

标准 I/O 库是标准 C 库中用于文件 I/O 操作(譬如读文件、写文件等)相关的一系列库函数的集合,通常标准 I/O 库函数相关的函数定义都在头文件<stdio.h>中,所以我们需要在程序源码中包含<stdio.h>头文件。

标准 I/O 库函数是构建于文件 I/O 这些系统调用之上的,譬如标准 I/O 库函数 fopen()就利用系统调用 open()来执行打开文件的操作、fread()利用系统调用 read()来执行读文件操作、fwrite()则利用系统调用 write()来执行写文件操作等等。

打开文件

代码语言:javascript
复制
#include <stdio.h>

FILE *fopen(const char *path, const char *mode);

读写文件

代码语言:javascript
复制
#include <stdio.h>

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
标准 I/O 和文件 I/O 的区别如下:

⚫ 虽然标准 I/O 和文件 I/O 都是 C 语言函数,但是标准 I/O 是标准 C 库函数,而文件 I/O 则是 Linux 系统调用;

⚫ 标准 I/O 是由文件 I/O 封装而来,标准 I/O 内部实际上是调用文件 I/O 来完成实际操作的;

⚫ 可移植性:标准 I/O 相比于文件 I/O 具有更好的可移植性,通常对于不同的操作系统,其内核向应用层提供的系统调用往往都是不同,譬如系统调用的定义、功能、参数列表、返回值等往往都是不一样的;而对于标准 I/O 来说,由于很多操作系统都实现了标准 I/O 库,标准 I/O 库在不同的操作系统之间其接口定义几乎是一样的,所以标准 I/O 在不同操作系统之间相比于文件 I/O 具有更好的可移植性。

⚫ 性能、效率:标准 I/O 库在用户空间维护了自己的 stdio 缓冲区,所以标准 I/O 是带有缓存的,而文件 I/O 在用户空间是不带有缓存的,所以在性能、效率上,标准 I/O 要优于文件 I/O。

所有文件 I/O 函数都是围绕文件描述符进行的,调用 open()函数打开一个文件时,即返回一个文件描述符 fd,然后该文件描述符就用于后续的 I/O 操作。对于标准 I/O 库函数来说,它们的操作是围绕 FILE 指针进行的,当使用标准 I/O 库函数打开或创建一个文件时,会返回一个指向 FILE 类型对象的指针(FILE *),使用该 FILE 指针与被打开或创建的文件相关联,然后该 FILE 指针就用于后续的标准 I/O 操作。

·················· END ··················

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 嵌入式Linux系统开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文件IO
  • 标准IO
    • 标准 I/O 和文件 I/O 的区别如下:
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档