linux文件I/O之 close()、lseek()、read()、write() 函数用法

 1. close() 函数

头文件和函数声明

#include <unistd.h>

int close(int fd);

函数功能

关闭一个文件描述符

返回值

成功时返回 0。失败则返回 -1,并设置 errno 为相应的错误标志。

参数

fd:文件描述符

说明

像其它所有系统调用一样,应对 close() 的调用进行错误检查,如下所示:

if (-1 == close(fd)) {

        perror("close error");

        exit(EXIT_FAILURE);

}

以上代码能够捕获的错误有: 

  • 企图关闭一个未打开文件描述符。
  • 多次关闭同一个文件描述符。
  • 捕获特定文件系统在关闭操作时诊断出的错误,例如:NFS(网络文件系统),如果 NFS 出现提交失败,这意味着数据没有抵达远程磁盘,随之将这一错误作为 close() 调用失败的原因传递给应用程序。

例子

以下程序功能:打开 "./log.txt" 文件,然后调用 close() 函数关闭打开的文件

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int flags = O_WRONLY | O_CREAT | O_APPEND; /* 只写,没有该文件则创建,写时从文件内容的末尾附加新内容 */mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /* rw-rw-rw- */int fd = open("./log.txt", flags, mode); if (fd < 0) {perror("open error");exit(EXIT_FAILURE);}int ret = close(fd); /* 关闭文件描述符 */if (ret < 0) {perror("close error");exit(EXIT_FAILURE);}printf("process exit success\n");return 0;
}

 2. lseek() 函数

        每个打开的文件都有一个与其相关联的当前文件偏移量(current file offset),它通常是一个非负整数,用以度量从文件开始处计算的字节数。

        读写操作都从当前文件偏移量开始,并使偏移量增加所读写的字节数。

        系统默认的情况,当打开一个文件时,除非指定 O_APPEND 选项打开,否则该偏移量被设置为 0。可以调用 lseek() 函数为一个打开的文件设置偏移量。 

头文件和函数声明

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

typedef long off_t;

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

函数功能

为一个打开的文件设置偏移量

返回值

成功返回新的文件偏移量,失败返回 -1,并设置 errno 为相对应的错误标志。(注意:成功返回新的文件偏移量可能为负数,所以在判断 lseek() 函数一定要谨慎,应该判断返回值是否等于 -1

参数

fd:文件描述符

offset:参数 offset 的含义跟参数 whence 的值有关

  • whence = SEEK_SET 时,则将文件的偏移量设置为文件开始处 offset 个字节,参数 offset 必须为非负数。
  • whence = SEEK_CUR 时,则将文件的偏移量设置为 当前文件的偏移量 + offset 个字节,参数 offset 可以为正数,也可以为负数。
  • whence = SEEK_END 时,则将文件的偏移量设置为 文件长度 + offset 个字节,参数 offset 可以为正数,也可以为负数。

off_t new_offset = lseek(fd, 0, SEEK_SET);         // 将 fd 引用的文件的文件偏移量设置到文件开始处

off_t new_offset = lseek(fd, 0, SEEK_END);        // 将 fd 引用的文件的文件偏移量设置到文件尾部

off_t new_offset = lseek(fd, -1, SEEK_END);       // 将 fd 引用的文件的文件偏移量设置到文件尾部的前一个字节处

 linux 内核中对 SEEK_SET、SEEK_CUR、SEEK_END 的定义如下所示:

#define SEEK_SET	0	/* seek relative to beginning of file */
#define SEEK_CUR	1	/* seek relative to current file position */
#define SEEK_END	2	/* seek relative to end of file */

例子

以下程序功能:打开 "./log.txt" 文件,调用 lseek() 函数将文件偏移量设置为文件尾部,然后从文件尾部开始写入 “hello world\n” 字符串,最后调用 close() 函数关闭打开的文件

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int flags = O_WRONLY | O_CREAT; /* 只写,没有该文件则创建,文件偏移量默认为 0 */mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /* rw-rw-rw- */int fd = open("./log.txt", flags, mode); if (fd < 0) {perror("open error");exit(EXIT_FAILURE);}off_t new_offset = lseek(fd, 0, SEEK_END); // 将文件偏移量设置为文件尾部,也可用于获取文件长度(文件所占字节数)的方法if (-1 == new_offset) {perror("lseek error");exit(EXIT_FAILURE);}off_t length = new_offset;printf("before write, file length = %ld\n", length);char buf[] = "hello world\n"; // strlen(buf) = 12; sizeof(buf) = 13ssize_t nwrite = write(fd, buf, strlen(buf));if (nwrite < 0) {perror("write error");exit(EXIT_FAILURE);}length = lseek(fd, 0, SEEK_END);if (-1 == length) {perror("lseek error");exit(EXIT_FAILURE);}printf("after write, file length = %ld\n", length);if (-1 == close(fd)) {perror("close error");exit(EXIT_FAILURE);}return 0;
}

3. read() 函数

头文件和函数声明

#include <unistd.h>

/********************/

/* 32位系统 */

typedef unsigned int size_t ;

typedef int ssize_t ;

/* 64位系统 */

typedef unsigned long size_t ;

typedef long ssize_t;

/********************/

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

函数功能

从文件描述符 fd 引用的文件中请求读取 count 字节的数据并存储到从 buf 开始的缓冲区中

返回值

  • 如果 read() 成功,将返回实际读取到的字节数。
  • 如果遇到文件结尾(EOF)则返回 0。
  • 如果读取失败,则返回 -1,并设置 errno 为相应的错误标志。

说明

一次 read() 调用所读取到的字节数可能会小于请求的字节数

  • 对于普通文件而言,这可能读取到靠近文件尾部了。
  • 对于其它文件类型,比如管道、FIFO、socket 或终端,在不同环境下也会出现读取到的字节数小于请求的字节数。例如,默认情况下,从终端读取字符,遇到换行符(\n),read() 调用就会返回。

参数

fd:文件描述符

buf:存储读取到的数据的首地址

count:请求读取 count 字节数据

4. write() 函数

头文件和函数声明

#include <unistd.h>

/********************/

/* 32位系统 */

typedef unsigned int size_t ;

typedef int ssize_t ;

/* 64位系统 */

typedef unsigned long size_t ;

typedef long ssize_t;

/********************/

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

函数功能

向文件描述符 fd 引用的文件中写入从 buf 开始的缓冲区中 count 字节的数据。

返回值

成功时返回被写入的字节数(若为 0 则表示没有写入数据)。失败则返回 -1,并设置 errno 为相应的错误标志。

参数

fd:文件描述符

buf:要被写入文件的数据在内存中的首地址

count:请求写入 count 字节

说明

如果 write() 调用成功,将会返回实际写入文件的字节数。该返回值可能会小于 count 参数值,这被叫做部分写。

  • 对于磁盘文件来说,造成部分写的原因可能是磁盘已满,或是因为进程资源对文件大小的限制
  • 对于磁盘文件执行 I/O 操作时,write() 调用成功并不能保证已经完成写入磁盘,因为为了减少磁盘活动量和加快 write() 系统调用,内核会缓存磁盘的 I/O 操作

例子

以下程序功能:拷贝一个普通文件。命令行格式:./copyfile_demo log.txt log2.txt

#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>#define BUF_SIZE 4096int main(int argc, char *argv[])
{if (argc != 3) {printf("%s input_file out_put_file\n", argv[0]);exit(EXIT_FAILURE);}int ifd = open(argv[1], O_RDONLY); // 只读方式打开if (-1 == ifd) {fprintf(stderr, "open %s error: %s\n", argv[1], strerror(errno));exit(EXIT_FAILURE);}int flags = O_WRONLY | O_CREAT | O_EXCL; // 只读,创建新文件,O_EXCL:此标志,保证 open() 调用只能创建新文件,如果文件存在则报错int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /* rw-rw-rw- */int ofd = open(argv[2], flags, mode);if (-1 == ofd){if (-1 == close(ifd))perror("close error");fprintf(stderr, "open %s error: %s\n", argv[2], strerror(errno));exit(EXIT_FAILURE);}char buf[BUF_SIZE] = "";ssize_t nread = 0;while ((nread = read(ifd, buf, BUF_SIZE)) > 0) {if (write(ofd, buf, nread) != nread) {if (-1 == close(ifd))perror("close error");if (-1 == close(ofd))perror("close error");perror("write error");exit(EXIT_FAILURE);}}// 成功 read() 完整个文件,nread = 0if (-1 == nread) {if (-1 == close(ifd))perror("close error");if (-1 == close(ofd))perror("close error");perror("read error");exit(EXIT_FAILURE);}if (-1 == close(ifd))perror("close error");if (-1 == close(ofd))perror("close error");printf("copy %s success\n", argv[1]);return 0;
}

 注:对实例代码中 open() 函数有疑惑的小伙伴,欢迎浏览我的这篇博文,这里就不再过多阐述。

linux文件I/O之 open() 函数用法_微尘8的博客-CSDN博客

参考:

《UNIX环境高级编程》(第3版)

《Linux-UNIX系统编程手册》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/84444.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二级python和二级c哪个简单,二级c语言和二级python

大家好&#xff0c;小编为大家解答二级c语言和二级office一起报可以吗的问题。很多人还不知道计算机二级c语言和python哪个好考&#xff0c;现在让我们一起来看看吧&#xff01; 介绍Python有很多库和使用Qt编写的接口,这自然创建c调用Python的需求。一路摸索,充满艰辛的添加头…

创建型模式-原型模式

文章目录 一、原型模式1. 概述2. 结构3. 实现4. 案例1.5 使用场景1.6 扩展&#xff08;深克隆&#xff09; 一、原型模式 1. 概述 用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 2. 结构 原型模式包含如下角色&#xff1a; …

8月10日上课内容 Tomacat部署及优化

tomcat 开放源代码的web应用服务器。基于java代码开发的。 Tomcat介绍 tomcat就是处理动态请求和基于java代码的页面开发 可以在html当中写入java代码&#xff0c;tomcat可以解析html页面当中的java,执行动态请求&#xff0c;动态页面。缺点是机制有问题:不对tomcat进行优化&…

Hello,SpringBoot!

一、回顾什么是Spring Spring是一个开源框架&#xff0c;2003 年兴起的一个轻量级的Java 开发框架&#xff0c;作者&#xff1a;Rod Johnson Spring是为了解决企业级应用开发的复杂性而创建的&#xff0c;简化开发。 Spring是如何简化Java开发的 为了降低Java开发的复杂性…

mac安装nvm管理工具遇到的问题和解决方法

nvm 是一款可以管理多版本node的工具&#xff0c;因为是刚买没多久的电脑之前用的都是windows&#xff0c;昨天折腾了一下午终于倒腾好了 第一步&#xff1a; 卸载电脑已有的node&#xff1b;访问nvm脚本网址&#xff0c;另存为到电脑上任何目录&#xff0c;我是放在桌面上的…

【pinia】Pinia入门和基本使用:

文章目录 一、 什么是pinia二、 创建空Vue项目并安装Pinia1. 创建空Vue项目2. 安装Pinia并注册 三、 实现counter四、 实现getters五、 异步action六、 storeToRefs保持响应式解构七、基本使用&#xff1a;【1】main.js【2】store》index.js【3】member.ts 一、 什么是pinia P…

使用一个python脚本抓取大量网站【2/3】

一、说明 我如何使用一个 Python 脚本抓取大量网站&#xff0c;在第 2 部分使用 Docker &#xff0c;“我如何使用一个python脚本抓取大量网站”统计数据。在本文中&#xff0c;我将与您分享&#xff1a; Github存储库&#xff0c;您可以从中克隆它;链接到 docker 容器&#xf…

【Docker】Windows下docker环境搭建及解决使用非官方终端时的连接问题

目录 背景 Windows Docker 安装 安装docker toolbox cmder 解决cmder 连接失败问题 资料获取方法 背景 时常有容器方面的需求&#xff0c;经常构建调试导致测试环境有些混乱&#xff0c;所以想在本地构建一套环境&#xff0c;镜像调试稳定后再放到测试环境中。 Windows …

缓存平均的两种算法

引言 线边库存物料的合理性问题是物流仿真中研究的重要问题之一,如果线边库存量过多,则会对生产现场的布局产生负面影响,增加成本,降低效益。 写在前面 仿真分析后对线边Buffer的使用情况进行合理的评估就是一个非常重要的事情。比较关心的参数包括:缓存位最大值…

k8s-----集群调度

目录 一&#xff1a;调度约束 二&#xff1a;Pod 启动创建过程 三&#xff1a;k8s调度过程 1、Predicate 有一系列的常见的算法 2、常见优先级选项 3、指定调度节点 &#xff08;1&#xff09;nodeName指定 &#xff08;2&#xff09;nodeSelector指定 四&#xff1a;亲和…

基于金融行业的软件测试分析

随着银行业务不断增加&#xff0c;业务模式不断复杂化&#xff0c;对我们的银行软件也要求越来越高&#xff0c;产出高质量的产品也非常重要&#xff0c;下面对银行软件测试进行分析总结。 银行软件集中度高&#xff0c;规模庞大&#xff0c;往往是以系统群的方式存在&#xff…

【算法篇C++实现】五大常规算法

文章目录 &#x1f680;一、分治法⛳&#xff08;一&#xff09;算法思想⛳&#xff08;二&#xff09;相关代码 &#x1f680;二、动态规划算法⛳&#xff08;一&#xff09;算法思想⛳&#xff08;二&#xff09;相关代码 &#x1f680;三、回溯算法⛳&#xff08;一&#xf…

ELK 将数据流转换回常规索引

ELK 将数据流转换回常规索引 现象&#xff1a;创建索引模板是打开了数据流&#xff0c;导致不能创建常规索引&#xff0c;并且手动修改、删除索引模板失败 "reason" : "composable template [logs_template] with index patterns [new-pattern*], priority [2…

微服务Ribbon-负载均衡策略和饥饿加载

目录 一、负载均衡策略 1.1 负载均衡策略介绍 1.2 自定义负载均衡策略 二、饥饿加载 &#xff08;笔记整理自bilibili黑马程序员课程&#xff09; 一、负载均衡策略 1.1 负载均衡策略介绍 负载均衡的规则都定义在IRule接口中&#xff0c;而IRule有很多不同的实现类&…

uniapp 格式化时间刚刚,几分钟前,几小时前,几天前…

效果如图&#xff1a; 根目录下新建utils文件夹&#xff0c;文件夹下新增js文件&#xff0c;文件内容&#xff1a; export const filters {dateTimeSub(data) {if (data undefined) {return;}// 传进来的data必须是日期格式&#xff0c;不能是时间戳//将字符串转换成时间格式…

Vue3使用wangEditor

那么这一节我们在编辑公司信息的弹窗中使用富文本插件wangEditor官网 Vue3使用wangEditor 安装wangEditor在弹窗中引入wangEditor结构api接口部分editor组件script部分怎么去修改富文本的编辑器&#xff1f; 案例内效果&#xff1a; 安装wangEditor npm install wangeditor/…

RabbitMQ学习——发布订阅/fanout模式 topic模式 rabbitmq回调确认 延迟队列(死信)设计

目录 引出点对点(simple)Work queues 一对多发布订阅/fanout模式以登陆验证码为例pom文件导包application.yml文件rabbitmq的配置生产者生成验证码&#xff0c;发送给交换机消费者消费验证码 topic模式配置类增加配置生产者发送信息进行发送控制台查看 rabbitmq回调确认配置类验…

MySQL 存储过程、函数、触发器、事件

​ 目录 存储过程 创建存储过程 调用存储过程 查看存储过程 删除存储过程 进阶 变量 if条件判断 传递参数 case结构 while循环 repeat结构 loop语句 leave语句 游标/光标 存储函数 触发器 创建触发器 删除触发器 查看触发器 事件 查看事件调度器是否开启…

大模型在金融医疗、生命系统和物理仿真领域的创新应用探索

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 在当今迅速发展的科技领域&#xff0c;大模型技术正日益成为金融医疗、生命系统和物理仿真等领域中的重要工具。2023年6月16日&#xff0c;AI TIME举办的青年科学家大模型专场活动邀请了国防科技大学理学院数学…

[系统安全] 五十二.DataCon竞赛 (1)2020年Coremail钓鱼邮件识别及分类详解

您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列。因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全、逆向分析和恶意代码检测,“系统安全”系列文章会更加聚焦,更加系…