【Linux学习笔记】7. Linux文件IO详解(附代码实例)

2023-11-18

Linux文件I/O

# 前置知识

  • Linux文件I/O分为系统IO和标准IO,常用于系统编程

  • 系统I/O通过文件描述符 fd 来操作文件

  • 标准I/O通过文件流 FILE* 来操作文件

  • Linux下可以使用man命令来查看使用手册

学习和使用这些API最快的途径是利用系统自带的man查看手册,查看系统IO可以用man 2 open, 查看标准I/O可以用man 3 fopen

关于linux中man 1 2 3 … 的区别 :

1、Standard commands (标准命令)
2、System calls (系统调用)
3、Library functions (库函数)
4、Special devices (设备说明)
5、File formats (文件格式)
6、Games and toys (游戏和娱乐)
7、Miscellaneous (杂项)
8、Administrative Commands (管理员命令)
9、 其他(Linux特定的), 用来存放内核例行程序的文档。

# 系统I/O

常用的系统I/O接口有:

  • open()
  • read()
  • write()
  • close()
  • lseek()
1. open()

使用命令man 2 open查看使用手册

头文件:

使用open()函数需要包含以下头文件:

#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);

函数参数:

参数 意义
pathname 打开/创建的文件名
flags 文件的打开模式,常用O_RDONLY, O_WRONLY, O_RDWR
mode 创建文件时需要指定,用来设置创建文件的权限(rwx)

返回值:

  • 返回值类型:int
  • 调用成功时返回一个文件描述符fd
  • 调用失败时返回-1,并设置errno

关于函数的参数说明:

第二个参数flags可以指定为以下宏:

  • O_RDONLY : 只读打开
  • O_WRONLY : 只写打开
  • O_RDWR : 读写打开
  • O_APPEND:以追加模式打开
  • O_CREAT:若文件不存在,则创建该文件,同时需要指定第三个参数
  • O_SYNC:使每次write都等到物理I/O操作完成
  • O_TRUNC:若此文件存在,并以读写或只写打开,则文件长度为0(打开文件的同时将文件中的内容清除)
  • O_EXCL:若同时设置O_CREAT标志且文件已存在,则会出错。可用于测试文件是否存在
  • O_NOCTTY:若打开的文件是终端设备,则不将此设备设置为进程的控制终端
  • O_NONBLOCK:若打开的文件是管道、块设备文件或字符设备文件,则后续的I/O操作均设置为非阻塞方式

以上关于flags的参数只有前三个指定读写方式的参数必须唯一,其他都可以用或运算符|同时指定多个宏。

第三个参数mode可以指定为以下宏:

image-20220420134637818

linux环境下使用命令man 2 open打开的手册中关于flags指定了O_CREAT时的第三参数选项,学过Linux文件权限都能理解手册的内容。

2. read()

使用命令man 2 read查看使用手册

头文件:

使用read()函数需要包含头文件:#include <unistd.h>

函数原型:

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

函数参数:

参数 意义
fd 即将读取文件的文件描述符
buf 存储读入数据的缓冲区
count 将要读入的数据的个数

返回值:

  • 返回值类型是:ssize_t,32位机上等同于int
  • 成功时返回读取的字节数
  • 出错时返回EOF,读到文件末返回0
3. write()

使用命令man 2 write查看使用手册

头文件:

使用write()函数需要包含头文件:#include <unistd.h>

函数原型:

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

函数参数:

参数 意义
fd 即将读取文件的文件描述符
buf 要写入的数据缓冲区
count 写入数据的个数,大小不应该大于buf大小

返回值:

  • 返回值类型为:ssize_t
  • 成功时返回写入的字节数
  • 出错时返回EOF,读到文件末返回0
4. close()

使用命令man 2 close查看使用手册

头文件:

使用close()时需要包含头文件: #include <unistd.h>

函数原型:

int close(int fd);

函数参数:

  • fd: 要关闭的文件描述符。

返回值:

  • 关闭成功时返回0,出错时返回EOF.。

说明:

  • 程序在结束时会自动关闭所有打开的文件。
  • 文件被关闭后,再对文件进行任何操作都是无意义的。
5. lseek()

使用命令man 2 lseek查看使用手册

头文件:

使用lseek()函数需要包含头文件:

#include <sys/types.h>
#include <unistd.h>

函数原型:

 off_t lseek(int fd, off_t offset, int whence);

函数参数:

参数 意义
fd 文件描述符
offset 偏移量,可正可负
whence 指定一个基准点,基准点+偏移量等于当前位置

返回值:

  • 返回值类型为:off_t, 32位机等同于int
  • 成功时则返回目前的读写位置, 也就是距离文件开头多少个字节
  • 出错时返回-1, errno 会存放错误代码.

关于函数的参数说明:

第三个参数whence

  • SEEK_SET:基准点为文件开头
  • SEEK_CUR:基准点为当前位置
  • SEEK_END:基准点为文件长度(可以理解为文件末尾)

image-20220420172549752

系统IO实例——文件复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	if(argc != 3) {	//argv第一个参数为自身文件名,因此需要再指定两个文件
		printf("error\n");
		exit(1);	//使用exit()需要包含头文件<stdlib.h>
	}
	//打开文件
	int fd_from = open(argv[1], O_RDONLY);	//第二个参数为copy的源文件
	if(-1 == fd_from) {
		perror("open1");
		exit(2);
	}
	int fd_to = open(argv[2], O_WRONLY | O_CREAT, S_IRWXU);	//第三个参数为copy的目标文件
	if(-1 == fd_to) {
		perror("open2");
		exit(3);
	}
	
	char buff[128] = {0};
	ssize_t ret;
	while(1) {	//每次读写128个字节,直到文件结束
		ret = read(fd_from, buff, sizeof(buff) - 1);
		if(-1 == ret) {
			perror("read");
		}
		else if(0 == ret) {	//read()返回0则文件结束了
			printf("finish copy\n");
			break;	
		}
		ret = write(fd_to, buff, ret);
		if(-1 == ret) {
			perror("write");
		}
	}
	//关闭文件
	close(fd_from);
	close(fd_to);
	return 0;
}

# 标准I/O

  • 与系统I/O不同的是,标准I/O带有缓冲区,可以减少系统调用,提高系统效率。

常用的标准I/O接口有:

  • fopen()
  • fread()
  • fwrite()
  • fclose()

使用标准I/O只需包含头文件:#inlcude <stdio.h>

1. fopen()

函数原型:

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

函数参数:

参数 意义
path 打开/创建的文件名
mode 文件的打开模式

关于mode的选项有:r只读,r+读写;w只写,w+读写,a追加写,a+追加读写。其中除了r和r+其他都会在文件不存在时创建文件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ypi7jjAB-1650468046692)(https://cdn.jsdelivr.net/gh/Chen-Mxn/mx-picgo-image/20220420173628.png)]

返回值:

  • 成功时返回一个文件流指针:FILE*
  • 失败时返回NULL
2. fread()

函数原型:

 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

函数参数:

参数 意义
ptr 接收数据的地址,最小尺寸size*nmemb字节
size 每次读取的一个单元的大小,单位字节
nmemb 读取的单元个数
stream 即将读取文件的文件流

返回值:

  • 返回值类型为:size_t,在32位机等价于unsigned int
  • 成功时返回实际读取的单元个数
  • 文件结束或读取出错时返回0或一个小于nmemb的数
3. fwrite()

函数原型:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

函数参数:

参数 意义
ptr 要写入文件的数据的地址
size 每次写入的一个单元的大小
nmemb 写入的单元个数
stream 即将写入文件的文件流

返回值:

  • 返回值类型为:size_t
  • 成功时返回实际写入的单元个数
  • 出错时返回一个与nmemb不同的数
4. fclose()

函数原型:

int fclose(FILE *stream);

函数参数:

  • stream: 要关闭的文件流指针

返回值:

  • 成功时返回0
  • 失败时返回EOF,并设置errno
标准IO实例——文件复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	if( argc != 3) {
		printf("error! please input 2 file name");
		exit(1);
	}
	//打开文件
	FILE *fp_from = fopen(argv[1], "r");	//只读
	if(NULL == fp_from) {
		perror("fopen1");
		exit(2);
	}
	
	FILE *fp_to = fopen(argv[2], "w");	//只写
	if(NULL == fp_to) {
		perror("fopen2");
		exit(3);
	}

	size_t size;
	char buff[128] = {0};
	while(1) {	//每次128字节不断读写
		size = fread(buff, 1, sizeof(buff) - 1, fp_from);
		if(0 == size) {	//fread()返回0 文件结束即复制完成
			printf("finish copy\n");
			break;
		}

		size = fwrite(buff, 1, size, fp_to);
		if(0 == size) {
			perror("fwrite");
		}
        //每次读写完要把buff清空防止出错
		memset(buff, 0, sizeof(buff));
	}
	//关闭文件
	fclose(fp_from);
	fclose(fp_to);
	return 0;
}

# 系统IO与标准IO的区别

最大的区别在于:

  • 标准IO引用了缓冲机制,在每次执行标准IO操作时,所有的操作都在缓存区中执行,在系统空闲时或者缓冲区满的时候再写入物理磁盘,从而提高效率。
  • 系统IO没有缓冲机制,每次执行系统IO操作时都会进行硬盘的读写。

image-20220420172516786

2022.04.20

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux学习笔记】7. Linux文件IO详解(附代码实例) 的相关文章

  • 在 Ubuntu 上纯粹通过 bash 脚本安装 mysql 5.7

    我想要一个无需任何手动输入即可安装 MySQL 5 7 实例的 bash 脚本 我正在关注数字海洋教程 https www digitalocean com community tutorials how to install mysql
  • 如何在两个不同帐户之间设置无密码身份验证

    我们可以在两台机器的两种不同用途之间设置无密码身份验证吗 例如 计算机A有用户A 计算机B有用户B 我们可以设置密码 ssh 以便计算机 A 上的用户 A 使用其用户帐户 A 登录计算机 B 谢谢你 如果我理解你的问题 你能设置一下吗ssh
  • 编写多个mysql脚本

    是否可以在复合脚本中包含其他 mysql 脚本 理想情况下 我不想为包含的脚本创建存储过程 对于较大的项目 我想分层维护几个较小的脚本 然后根据需要组合它们 但现在 我很乐意学习如何包含其他脚本 source是一个内置命令 您可以在 MyS
  • 如何使用ffmpeg重叠和合并多个音频文件?

    我正在尝试将多个音频文件合并到一个文件中 但我可以使用以下命令来连接 而不是连接 ffmpeg v debug i file1 wav i file2 wav i file3 wav filter complex 0 0 concat n
  • 是否有可能在linux中找到包含特定文本的文件?

    考虑这种情况 我在文件夹 Example 下有很多文件 如果我需要找到一个包含特定短语 如 Class Example 的文件 我该如何使用 Linux shell 来做到这一点 linux中有类似 定位 的函数可以做到这一点吗 Thank
  • CPAN shell 内存不足。在 Unix 上如何给它更多的内存?

    我得到一个Out of memory 所有安装的消息 我以前从未使用过 cpan 并且不太确定它是如何工作的 我做了一个ulimit在 cpan 目录中 结果是无限的 这是我正在看的内容 usr bin perl MCPAN e shell
  • 错误:NVIDIA-SMI 失败,因为无法与 NVIDIA 驱动程序通信

    NVIDIA SMI 抛出此错误 NVIDIA SMI 失败 因为无法与 NVIDIA 通信 司机 确保安装了最新的 NVIDIA 驱动程序并且 跑步 我清除了 NVIDIA 并按照提到的步骤重新安装了它here https askubun
  • 如何从类似于 eclipse 的命令行创建可运行的 jar 文件

    我知道 eclipse 会生成一个可运行的 jar 文件 其中提取并包含在该 jar 文件中的所有库 jar 文件 从命令提示符手动创建 jar 文件时如何执行类似的操作 我需要将所有 lib jar 解压到类文件夹中吗 目前我正在使用 j
  • 为 Linux 安装 R 包时出错

    我试图在 R 3 3 上安装一个名为 rgeos 的包 但是当我输入 install packages rgeos 但它返回给我以下错误 其他包也会发生同样的情况 但不是所有包 gt installing source package rg
  • 如何从 Linux 命令行获取视频文件的分辨率(宽度和高度)?

    我一直在挖掘 mplayer mencoder 和 ffmpeg 文档 但我似乎无法想出anything 我对输出格式不是特别挑剔 因为我可以使用正则表达式将其拉出来 我只是似乎无法首先获取数据 Use ffprobe https ffmp
  • 无法仅在控制台中启动 androidstudio

    你好 我的问题是下一个 我下载了Android Studio如果我去 路径 android studio bin 我执行studio sh 我收到以下错误 No JDK found Please validate either STUDIO
  • 如何查明 Ubuntu 上安装了哪个版本的 GTK+?

    我需要确定 Ubuntu 上安装了哪个版本的 GTK 男人似乎不帮忙 这个建议 https stackoverflow com a 126145 会告诉您安装了哪个 2 0 的次要版本 不同的主要版本将具有不同的包名称 因为它们可以在系统上
  • 类unix系统中的python和python3命令有什么区别?

    我通读了每个命令的描述 但每个命令的描述都是完全相同的 所以我不明白这两个命令在类 Unix 系统中的工作方式有何不同 谁能解释其中的区别吗 Python3命令的引入是因为python命令指向了python2 从那时起 Python3 已成
  • 将数组传递给函数名称冲突

    Specs GNU bash 版本 3 1 17 无法升级 Premise 我一直在摆弄数组 我想知道是否有任何方法可以让函数的本地变量与所述函数外部的数组同名 Example 在下面的示例中 我将尝试显示该问题 Working bin b
  • numpy 未定义符号:PyFPE_jbuf

    我正在尝试使用一百万首歌曲数据集 为此我必须安装 python 表 numpy cython hdf5 numexpr 等 昨天我设法安装了我需要的所有内容 在使用 hdf5 遇到一些麻烦之后 我下载了预编译的二进制包并将它们保存在我的 b
  • git在Windows和Linux之间切换后强制刷新索引

    我有一个Windows和Linux共享的磁盘分区 格式 NTFS 它包含一个 git 存储库 约 6 7 GB 如果我只使用Windows or 只使用Linux操作 git 存储库一切正常 但是每次切换系统的时候git status命令将
  • 伊迪德信息

    重新定义问题 有什么方法可以获取所连接显示器的序列号吗 我想收集显示器的Eid信息 当我使用 logverbose 选项运行 X 时 我可以从 xorg 0 log 文件中获取它 但问题是 如果我切换显示器 拔出当前显示器 然后插入另一个显
  • 停止服务时单元陷入故障状态(状态=143)[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 这是我的问题 我有 CentOS 和 java 进程在上面运行 Java进程是通过启动 停止脚本来操作的 它也创建了 java 实例的 p
  • 标准头文件中的 C 编译器错误 - 未定义的 C++ 定义

    我正在尝试编译 C 程序 但收到许多错误 这些错误是在标准 C 头文件 inttypes h stdio h stat h 等 中遇到的 错误的来源是以下未定义的常量 BEGIN DECLS END DECLS BEGIN NAMESPAC
  • 无法执行'x86_64-conda_cos6-linux-gnu-gcc':没有这样的文件或目录(pysam安装)

    我正在尝试安装 pysam 执行后 python path to pysam master setup py build 这个错误的产生是 unable to execute x86 64 conda cos6 linux gnu gcc

随机推荐

  • 【Linux】【Ubuntu】在VMware虚拟机中安装Ubuntu18.04(UEFI启动图文教程)

    在VMware虚拟机中安装Ubuntu18 04 以UEFI方式启动 VMware 版本 15 5 以UEFI启动的Ubuntu系统安装方式与 Linux Ubuntu 在VMware虚拟机中安装Ubuntu18 04 保姆级图文教程 中记
  • BeagleBone 实施 Yocto 项目

    特点 Yocto 项目生产工具和流程 支持为嵌入式软件创建 Linux 发行版 独立于架构 BeagleBone Black 是一个平台 允许用户根据自己的喜好快速轻松地执行安装和自定义 从 Yocto Project 构建系统的基本介绍开
  • SD卡读写实验(SPI模式)

    对于 SD 卡的 SPI 模式而言 采用的 SPI 的通信模式为模式 3 即 CPOL 1 CPHA 1 在 SD 卡 2 0 版 本协议中 SPI CLK 时钟频率可达 50Mhz SD 卡的 SPI 模式 只用到了 SDIO D3 SP
  • 第五届蓝桥杯—— 基础练习:数列特征

    问题描述 给出n个数 找出这n个数的最大值 最小值 和 输入格式 第一行为整数n 表示数的个数 第二行有n个数 为给定的n个数 每个数的绝对值都小于10000 输出格式 输出三行 每行一个整数 第一行表示这些数中的最大值 第二行表示这些数中
  • C++11中的原子操作(atomic operation)

    所谓的原子操作 取的就是 原子是最小的 不可分割的最小个体 的意义 它表示在多个线程访问同一个全局资源的时候 能够确保所有其他的线程都不在同一时间内访问相同的资源 也就是他确保了在同一时刻只有唯一的线程对这个资源进行访问 这有点类似互斥对象
  • AIops | 一文了解日志异常检测

    作者 李旭光 中国农业银行研发中心责编 晋兆雨出品 CSDN云计算头图 付费下载于视觉中国 背景介绍 日志是有关系统运行状态的描述 例如Linux的系统日志 数据库系统的日志以及分布式系统的日志等 日志是运维人员查看系统运行状态 寻找系统故
  • Java Eclipse进行断点调试

    如何调试Java程序 大家最开始学习Java 都会觉得IDE调试好高端有木有 其实很简单了 下文会尽量简单直观的教会你在Eclipse中调试 其他的IDE调试步骤也是类似的 1 在你觉得有错的地方设置断点 在代码行数前 点击右键 注意是右键
  • MATLAB基础语法总结

    主体参照 全网最全MATLAB学习归纳总结 建模学习必备 MATLAB讲解PPT和MATLAB官方帮助文档这里对该教程做一定的完善与汇总 1 MATLAB编辑器常用快捷键 1 1 编辑器窗口操作 编辑器窗口操作 自动整理代码 用鼠标选中代码
  • 【粉丝问答11】如何实现内网穿透

    本文章由网友 邓工 投稿 VX A18665908735 问题描述 起因 最近公司要做一个4G模块带GNSS 全球导航卫星系统 定位功能的产品 上传传感器数据和设备定位数据到服务器上 我们选择了simcom7600G一个支持全球通的4G模块
  • 基于Docker安装的MindSpore-1.2 GPU版本

    技术背景 在前面一篇博客中 我们介绍过MindSpore CPU版本的Docker部署以及简单的案例测试 当时官方还不支持GPU版本的Docker容器化部署 经过MindSpore团队的努力 1 2 0版本的MindSpore GPU终于推
  • XCTF攻防世界Web12道简单题

    0x00 准备 内容 在xctf官网注册账号 即可食用 目录 目录 0x01 view source2 0x02 get post3 0x03 robots4 0x04 backup6 0x05 Cookie7 0x06 disabled
  • SSE3和SSSE3 Intrinsics各函数介绍

    SIMD相关头文件包括 include
  • Linux入门篇-01 台式机安装Linux系统

    材料 台式机 U盘 内存大于8G CentOs7 下载地址 点击跳转 步骤一 U盘启动电脑 启动成功画面 选择第一个 按E 或者 Tab键 进行编辑 vmlinuz initrd initrd img inst stage2 hd LABE
  • 传感器响应时间与滤波器截止频率的关系

    1 传感器响应时间与滤波器截止频率的关系 详细看 https blog csdn net Old Street article details 108087826 2 滤波器中关于截止频率的理解 http www 360doc com co
  • 孤立森林算法(Isolation Forest Algorithm)Python实现

    孤立森林算法 Isolation Forest Algorithm Python实现 孤立森林算法是一种用于检测异常值的无监督机器学习算法 它通过构建一棵随机划分的二叉树来判断数据点的异常程度 以此来识别异常值 本文将介绍孤立森林算法的原理
  • ubuntu20.04 安装 Sophus库 slambook2

    ubuntu20 04 安装 Sophus库 slambook2 slambook2 实践部分 需要我们自行安装 sophus 库 但是相关的依赖很多 而且sophus分为模板类和非模板类两种 安装起来还是比较繁琐的 slambook2中采
  • QT在子线程发送信号给主线程,主线程信号槽函数没有反应的解决办法

    在编写线程时遇到了一个问题 即子线程发送信号给主线程 主线程信号槽函数没有反应 这个问题卡了半天 最终找到解决办法 自己记录一下 问题 在子线程的run函数发送了一个信号 在主函数中定义了一个信号槽函数用来响应这个信号 但是槽函数不执行 修
  • 我要写一篇关于酒店管理系统论文,请说一说酒店管理系统的研究背景

    酒店管理系统的研究背景是指针对旅游业和酒店业的扩大发展 以及客户服务需求的日益增加 许多酒店已经使用酒店管理系统来提高服务质量和管理效率 酒店管理系统的研究着重于通过使用软件和信息技术来有效地管理酒店的各项运营活动 从而提升酒店的服务质量
  • 机器学习之多元线性回归

    1 多元线性回归模型 定义 具有多个特征的线性回归模型 多元线性回归模型 见下图 多元线性回归总结 参数 模型 损失函数 梯度下降算法 见下图 注意 梯度下降算法每次都是同时更新wj和b 2 多维特征 多维特征 x1 x2 xn 其中xj表
  • 【Linux学习笔记】7. Linux文件IO详解(附代码实例)

    Linux文件I O 前置知识 Linux文件I O分为系统IO和标准IO 常用于系统编程 系统I O通过文件描述符 fd 来操作文件 标准I O通过文件流 FILE 来操作文件 Linux下可以使用man命令来查看使用手册 学习和使用这些