问题:同一个进程中,先后对同一个文件描述符进行写入 / 读取 操作,读写指针的位置导致读取内容失败

本文主要是介绍问题:同一个进程中,先后对同一个文件描述符进行写入 / 读取 操作,读写指针的位置导致读取内容失败,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文件‘读写指针’ / lseek 系统调用
  1. 在进行文件操作(读 / 写)时,可以使用 lseek 系统调用来设置文件的下一个读写位置。
  2. 多进程 / 多线程 环境中,对同一资源进行读 / 写操作时,很可能会 因为 ‘读写指针’ 的变化导致各种隐蔽的问题,这一点必须要仔细。
  3. lseek 系统调用(对文件描述符的读写指针进行设置,即可以用它来 设置文件的下一个读写位置
  4. open 函数的 O_APPEND 选项,会影响文件的 ‘读写指针’ 是否会在多个进程间共享(是:导致写操作 追加到文件末尾,否:导致写操作 相互覆盖)(尝试解决一个问题的最好方式是:立刻开始动手操作)
#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fildes, off_t offset, int whence);

实验代码如下:

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>void main(){// 以读写方式打开文件,如果文件不存在则新建,新建文件时文件权限为 ‘rw-r--r--’int fd = open("1111111111111.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);if(fd < 0){printf("error: open failed.\n");exit(EXIT_FAILURE);}// 先执行写入操作int res = write(fd, "abc", 3);if(res != 3){printf("error: write failed.\n");exit(EXIT_FAILURE);}char buf[10];// 尝试读取之前写入的内容res = read(fd, buf, 3);if(res > 0){buf[res] = '\0';printf("readed:%s\n", buf);}else if(res == 0){printf("EOF\n");}else{printf("error: read failed.\n");exit(EXIT_FAILURE);}
}

运行结果为:

  • 程序创建新文件后,立即执行写入操作,随后从中读取之前写入的数据
  • 问题是: read 调用返回 0,表示已经到达文件末尾。但实际上文件中是有数据的
ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test4 test4.c
ubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test4
EOF 	// 读取失败(到达文件末尾)
ubuntu@cuname:~/dev/beginning-linux-programming/test$ ls -l | grep 1111
-rw-r--r-- 1 ubuntu ubuntu    3 Apr  8 17:23 1111111111111.txt
ubuntu@cuname:~/dev/beginning-linux-programming/test$ cat 1111111111111.txt
abc

!!!突然想到可能是 ‘读写指针’ 的问题!!!
(***因为执行写入操作后,‘读写指针’ 始终指向文件的末尾!***)
修改程序代码如下(在写入成功后,设置 ‘读写指针’ 的位置):

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>void main(){int fd = open("1111111111111.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);if(fd < 0){printf("error: open failed.\n");exit(EXIT_FAILURE);}int res = write(fd, "abc", 3);if(res != 3){printf("error: write failed.\n");exit(EXIT_FAILURE);}// 设置文件的 ‘读写指针’ 的位置,// 将 ‘读写指针’ 相对于当前位置(即:文件末尾)向左偏移 res 个字节(即:回到指执行写入操作时的位置)。off_t off = lseek(fd, 0 - res, SEEK_CUR);if(off == -1){printf("error: lseek failed.\n");exit(EXIT_FAILURE);}char buf[10];res = read(fd, buf, 3);if(res > 0){buf[res] = '\0';printf("readed:%s\n", buf);}else if(res == 0){printf("EOF\n");}else{printf("error: read failed.\n");exit(EXIT_FAILURE);}
}

运行程序,结果如下(确实是文件 ’读写指针‘ 的问题!):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test4 test4.c
ubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test4
readed:abc 	// 输出正确

这篇关于问题:同一个进程中,先后对同一个文件描述符进行写入 / 读取 操作,读写指针的位置导致读取内容失败的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/586877

相关文章

Spring的RedisTemplate的json反序列泛型丢失问题解决

《Spring的RedisTemplate的json反序列泛型丢失问题解决》本文主要介绍了SpringRedisTemplate中使用JSON序列化时泛型信息丢失的问题及其提出三种解决方案,可以根据性... 目录背景解决方案方案一方案二方案三总结背景在使用RedisTemplate操作redis时我们针对

如何使用Lombok进行spring 注入

《如何使用Lombok进行spring注入》本文介绍如何用Lombok简化Spring注入,推荐优先使用setter注入,通过注解自动生成getter/setter及构造器,减少冗余代码,提升开发效... Lombok为了开发环境简化代码,好处不用多说。spring 注入方式为2种,构造器注入和setter

MySQL进行数据库审计的详细步骤和示例代码

《MySQL进行数据库审计的详细步骤和示例代码》数据库审计通过触发器、内置功能及第三方工具记录和监控数据库活动,确保安全、完整与合规,Java代码实现自动化日志记录,整合分析系统提升监控效率,本文给大... 目录一、数据库审计的基本概念二、使用触发器进行数据库审计1. 创建审计表2. 创建触发器三、Java

SpringBoot整合Dubbo+ZK注册失败的坑及解决

《SpringBoot整合Dubbo+ZK注册失败的坑及解决》使用Dubbo框架时,需在公共pom添加依赖,启动类加@EnableDubbo,实现类用@DubboService替代@Service,配... 目录1.先看下公共的pom(maven创建的pom工程)2.启动类上加@EnableDubbo3.实

Kotlin Map映射转换问题小结

《KotlinMap映射转换问题小结》文章介绍了Kotlin集合转换的多种方法,包括map(一对一转换)、mapIndexed(带索引)、mapNotNull(过滤null)、mapKeys/map... 目录Kotlin 集合转换:map、mapIndexed、mapNotNull、mapKeys、map

nginx中端口无权限的问题解决

《nginx中端口无权限的问题解决》当Nginx日志报错bind()to80failed(13:Permissiondenied)时,这通常是由于权限不足导致Nginx无法绑定到80端口,下面就来... 目录一、问题原因分析二、解决方案1. 以 root 权限运行 Nginx(不推荐)2. 为 Nginx

解决1093 - You can‘t specify target table报错问题及原因分析

《解决1093-Youcan‘tspecifytargettable报错问题及原因分析》MySQL1093错误因UPDATE/DELETE语句的FROM子句直接引用目标表或嵌套子查询导致,... 目录报js错原因分析具体原因解决办法方法一:使用临时表方法二:使用JOIN方法三:使用EXISTS示例总结报错原

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤

Ubuntu 24.04启用root图形登录的操作流程

《Ubuntu24.04启用root图形登录的操作流程》Ubuntu默认禁用root账户的图形与SSH登录,这是为了安全,但在某些场景你可能需要直接用root登录GNOME桌面,本文以Ubuntu2... 目录一、前言二、准备工作三、设置 root 密码四、启用图形界面 root 登录1. 修改 GDM 配

MySQL深分页进行性能优化的常见方法

《MySQL深分页进行性能优化的常见方法》在Web应用中,分页查询是数据库操作中的常见需求,然而,在面对大型数据集时,深分页(deeppagination)却成为了性能优化的一个挑战,在本文中,我们将... 目录引言:深分页,真的只是“翻页慢”那么简单吗?一、背景介绍二、深分页的性能问题三、业务场景分析四、