Linux系统文件IO

Linux系统文件IO

每个系统都有自己的专属函数,我们习惯称其为系统函数。系统函数并不是内核函数,因为内核函数是不允许用户使用的,系统函数就充当了二者之间的桥梁,这样用户就可以间接的完成某些内核操作了。

在前面介绍了文件描述符,在Linux系统中必须要使用系统提供的IO函数才能基于这些文件描述符完成对相关文件的读写操作。这些Linux系统IO函数和标准C库的IO函数使用方法类似,函数名称也类似,下边开始一一介绍。

1. open/close

1.1 open函数

在Linux系统编程中,open 函数用于打开一个文件,并返回一个文件描述符,该文件描述符在后续的文件操作中被用作文件的标识符。如果文件不存在, 就创建一个新文件, open 函数的原型如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>/*
open是一个系统函数, 只能在linux系统中使用, windows不支持
fopen 是标准c库函数, 一般都可以跨平台使用, 可以这样理解:- 在linux中 fopen底层封装了Linux的系统API open- 在window中, fopen底层封装的是 window 的 api
*/
// 打开一个已经存在的磁盘文件
int open(const char *pathname, int flags);
// 打开磁盘文件, 如果文件不存在, 就会自动创建
int open(const char *pathname, int flags, mode_t mode);

参数介绍:

  • path 是要打开的文件的路径名。
  • flags 是打开文件的标志,可以是以下一种或多种标志的组合:
    • O_RDONLY:只读方式打开文件。
    • O_WRONLY:只写方式打开文件。
    • O_RDWR:读写方式打开文件。
    • O_CREAT:如果文件不存在,则创建文件。
    • O_EXCL:与 O_CREAT 一同使用,确保文件不存在(文件存在的话创建失败),避免覆盖已存在的文件。
    • O_TRUNC:如果文件存在,并且以写入方式打开,将文件截断为空。
    • O_APPEND:以追加方式打开文件,即写入数据时将数据添加到文件末尾。
  • mode 是一个八进制数,指定文件的访问权限(仅在创建新文件时有效)。通常使用 S_IRUSRS_IWUSRS_IXUSR 等宏定义来设置文件权限。

open 函数返回一个非负整数作为文件描述符,如果出错则返回 -1。可以**使用该文件描述符进行后续的文件读写操作。**以下是一个简单的例子:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main() {int fd;// 打开文件 example.txt,如果不存在则创建,以读写方式打开fd = open("example.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);if (fd == -1) {perror("open");exit(EXIT_FAILURE);}// 使用文件描述符进行文件操作...// 关闭文件if (close(fd) == -1) {perror("close");exit(EXIT_FAILURE);}return 0;
}

请注意,错误处理是良好程序设计的一部分,上述示例中使用 perror 输出错误信息。

1.2 close函数

通过open函数可以让内核给文件分配一个文件描述符, 如果需要释放这个文件描述符就需要关闭文件。对应的这个系统函数叫做 close,函数原型如下:

#include <unistd.h>
int close(int fd);
  • 函数参数: fd 是文件描述符, 是open() 函数的返回值
  • 函数返回值: 函数调用成功返回值 0, 调用失败返回 -1
1.3 打开文件

文件open.c

// open.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>int main()
{// 打开文件int fd = open("abc.txt", O_RDWR); // 只读打开// int fd = open("./new.txt", O_CREAT|O_RDWR, 0664); // 创建新文件// int fd = open("./new.txt", O_CREAT|O_EXCL|O_RDWR); // 创建新文件之前, 先检测是否存在// 文件存在创建失败, 返回-1, 文件不存在创建成功, 返回分配的文件描述符if(fd == -1){printf("打开文件失败\n");}else{printf("fd: %d\n", fd);}close(fd);return 0;
}

在这里插入图片描述

2. read/write

2.1 read

read 函数用于从已打开的文件描述符中读取数据。其原型如下:

#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);

其中:

  • fd 是已打开文件的文件描述符。
  • buf 是用于存放读取数据的缓冲区的指针。
  • count 是要读取的字节数。

read 函数的返回值为实际读取的字节数,如果返回值为0,表示已到达文件末尾。如果返回值为-1,表示发生错误。

2.2 write

write 函数用于将数据写入到文件内部,在通过 open 打开文件的时候需要指定写权限,函数原型如下:

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);

其中:

  • fd 是已打开文件的文件描述符。
  • buf 是包含要写入数据的缓冲区的指针。
  • count 是要写入的字节数。

write 函数的返回值为实际写入的字节数。如果返回值为-1,表示发生错误。

2.3 测试程序(文件拷贝)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>int main() {// 1. 打开存在的文件a.txt, 读这个文件int fd1 = open("./a.txt", O_RDONLY);if (fd1 == -1) {perror("open-readfile");return -1;}// 2. 打开不存在的文件, 将其创建出来, 将从a.txt读出的内容写入这个文件中int fd2 = open("copy.txt", O_WRONLY | O_CREAT, 0664);if (fd2 == -1) {perror("open-writefile");return -1;}// 3. 循环读文件, 循环写文件char buf[4096];int len = -1;while ((len = read(fd1, buf, sizeof(buf))) > 0) {// 将读到的数据写到另一个文件中write(fd2, buf, len);}// 4.关闭文件close(fd1);close(fd2);return 0;}

在这里插入图片描述

3. lseek

lseek 函数用于在文件中定位文件偏移量(file offset)。它的原型如下:

#include <sys/types.h>
#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);

参数:

  • fd: 文件描述符, open() 函数的返回值, 通过这个参数定位打开的磁盘文件
  • offset: 偏移量,需要和第三个参数配合使用
  • whence: 通过这个参数指定函数实现什么样的功能
    • SEEK_SET: 从文件头部开始偏移 offset 个字节
    • SEEK_CUR: 从当前文件指针的位置向后偏移offset个字节
    • SEEK_END: 从文件尾部向后偏移offset个字节

返回值:

  • 成功: 文件指针**从头部开始计算总的偏移量**
  • 失败: -1
3.1 移动文件指针

主要可以进行这三种常用操作:

  • 文件指针移动到文件头部
lseek(fd, 0, SEEK_SET);
  • 得到当前文件指针的位置
lseek(fd, 0, SEEK_CUR);
  • 得到文件总大小
lseek(fd, 0, SEEK_END);
3.2 文件扩展

当我们需要下载很大的文件时, 磁盘紧张, 如果不能马上将文件下载到本地, 磁盘可能会被占用, 这时可以现将字符写入到目标文件中, 让扩展的文件和被下载的文件一样大即可

使用 lseek 函数进行文件拓展必须要满足一下条件:

  • 文件指针必须要偏移到文件尾部之后, 多出来的就需要被填充的部分。
  • 文件拓展之后,必须要使用 write()函数进行一次写操作(写什么都可以,没有字节数要求)。

文件扩展举例:

// lseek.c
// 拓展文件大小
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int fd = open("a.txt", O_RDWR);if(fd == -1){perror("open");return -1;}// 文件拓展, 一共增加了 1001 个字节lseek(fd, 1024, SEEK_END);write(fd, " ", 1);close(fd);return 0;
}

文件扩展前后文件的大小:

在这里插入图片描述

4. truncate/ftruncate

truncate/ftruncate 这两个函数的功能是一样的,可以对文件进行拓展也可以截断文件。使用这两个函数拓展文件比使用lseek要简单。这两个函数的函数原型如下:

// 拓展文件或截断文件
#include <unistd.h>
#include <sys/types.h>int truncate(const char *path, off_t length);- 
int ftruncate(int fd, off_t length);

参数:

  • path: 要拓展/截断的文件的文件名
  • fd: 文件描述符, open() 得到的
  • length: 文件的最终大小
  • 文件原来size > length,文件被截断, 尾部多余的部分被删除, 文件最终长度为length
  • 文件原来size < length,文件被拓展, 文件最终长度为length

返回值: 成功返回0; 失败返回值-1

truncate() 和 ftruncate() 两个函数的区别在于一个使用文件名一个使用文件描述符操作文件, 功能相同。

不管是使用这两个函数还是使用 lseek() 函数拓展文件,文件尾部填充的字符都是 0。

5. perror

一般当程序出错时, 会有一个错误号, 每个错误号对应着错误信息

得到错误号,去查询对应的头文件是非常不方便的,我们可以通过 perror 函数将错误号对应的描述信息打印出来

#include <stdio.h>
// 参数, 自己指定这个字符串的值就可以, 指定什么就会原样输出, 除此之外还会输出错误号对应的描述信息
void perror(const char *s);	

例子: 在前面几个代码中都用到了perror

在这里插入图片描述

出错时的提示是这样的

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

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

相关文章

【5G PHY】5G 物理层加速卡介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

vue3项目创建

安装node.js vue --version &#xff08;4.5.0以上&#xff09; npm install -g vue/cli vue create 项目名称 npm run dev 启动 npm run build 打包 ———————— vite 创建工程 npm create vuelatest npm i npm run dev 启动 npm run build 打包 项目结构…

CloudQuery 的过去、现在和未来

CloudQuery (后续简称「CQ」)这个产品从设计/研发到现在&#xff0c;一晃已经 5 年多时间了&#xff0c;在不断的完善中&#xff0c;也积累了不少的社区/企业用户&#xff0c;我意识到&#xff0c;CQ 已经从一个 Idea 变成了公众软件&#xff0c;开始有它的使命、责任和价值主张…

Pycharm恢复默认设置

window 系统 找到下方目录-->删除. 再重新打开Pycharm C:\Users\Administrator\.PyCharm2023.3 你的不一定和我名称一样 只要是.PyCharm*因为版本不同后缀可能不一样 mac 系统 请根据需要删除下方目录 # Configuration rm -rf ~/Library/Preferences/PyCharm* # Caches …

算法分析与设计 第二次课外作业

算法分析与设计 第二次课外作业 文章目录 算法分析与设计 第二次课外作业一. 单选题&#xff08;共4题&#xff0c;40分&#xff09;二. 填空题&#xff08;共5题&#xff0c;50分&#xff09;三. 判断题&#xff08;共1题&#xff0c;10分&#xff09; 一. 单选题&#xff08;…

「Verilog学习笔记」异步复位同步释放

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1nsmodule ali16 (input clk,input rst_n,input d,output reg dout );//*************code***********//reg rst0, rst1 ; always (posedge clk or negedge…

【QT搭建】搭建可以生成手机APP的环境

一.问题分析 1.在原来的QT版本上安装Android(不推荐) 此方法暂时未实践成功,记录调试过程,可跳过 如果原来安装过QT桌面级PC软件的,可能没有配置JDK和SDK就会在QT选项的设备栏目种看到报错的提示。 并且Kits的选项里面没有Android,所以解决的问题是,缺少Kit套件Andro…

drf知识-09

自定义频率类 # throttling 频率限制 # 简单方案 from rest_framework.throttling import SimpleRateThrottle class CommonThrottle(SimpleRateThrottle):rate 3/mdef get_cache_key(self, request, view):ip request.META.get(REMOTE_ADDR)return ip# 复杂方案---》通用方案…

【LeetCode-剑指offer】--15.找到字符串中所有字母异位词

15.找到字符串中所有字母异位词 方法&#xff1a;滑动窗口 class Solution {public List<Integer> findAnagrams(String s, String p) {List<Integer> ans new ArrayList<>();int m s.length(),n p.length();if(n > m){return ans;}int[] cnt1 new i…

YoloV7改进策略:AAAI 2024 最新的轴向注意力|即插即用,改进首选|全网首发,包含数据集和代码,开箱即用!

摘要 https://arxiv.org/pdf/2312.08866.pdf 本文提出了一种名为Multi-scale Cross-axis Attention(MCA)的方法,用于解决医学图像分割中的多尺度信息和长距离依赖性问题。该方法基于高效轴向注意力,通过计算两个平行轴向注意力之间的双向交叉注意力,更好地捕获全局信息。…

无人机集群反制与对抗技术探讨

源自&#xff1a;指挥与控制学报 作者&#xff1a;任 智 张 栋 唐 硕 王孟阳 李智军 “人工智能技术与咨询” 发布 摘 要 无人机集群系统是现代信息化战争体系对抗中重要的新质作战力量, 是未来网络化、智能化作战的关键发展方向. 随着无人集群系统装备实战化技术的…

第二十七章 正则表达式

第二十七章 正则表达式 1.正则快速入门2.正则需求问题3.正则底层实现14.正则底层实现25.正则底层实现36.正则转义符7.正则字符匹配8.字符匹配案例19.字符匹配案例211.选择匹配符&#xff08;|&#xff09;12.正则限定符{n}{n,m}&#xff08;1个或者多个&#xff09;*(0个或者多…

『华为云耀云服务器实战』|云服务器如何快速搭建个人博客(图文详解)

文章目录 引言一、云耀云服务器L实例介绍1.1 准备一个华为云耀云服务器1.2 重置实例密码1.3 利用xshell 远程连接 二、安装环境软件2.1 安装git准备远程拉取2.2 安装Docker 和 Docker compose 三、博客开源项目介绍3.1 操作界面展览 四、拉取项目搭建个人博客4.1 拉取项目进行配…

【linux kernel】linux的SPI框架分析

文章目录 一、linux内核中的SPI框架二、SPI核心的初始化三、SPI核心的数据结构1、struct spi_statistics2、struct spi_delay3、struct spi_device4、struct spi_driver5、struct spi_controller6、struct spi_res7、struct spi_transfer8、struct spi_message9、struct spi_bo…

CMake支持的编译平台和IDE

文章目录 简介支持的IDEVisual Studio支持示例 其他编译器和生成器支持MinGW示例 IDE集成Eclipse示例 实验性和特殊平台支持总结 简介 CMake是一个非常强大的跨平台自动化构建工具&#xff0c;它支持生成多种类型的项目文件&#xff0c;覆盖了广泛的开发环境和编译器。在这篇博…

基于PCA-WA(Principal Component Analysis-weight average)的图像融合方法 Matlab代码及示例

摘要&#xff1a; 高效地将多通道的图像数据压缩&#xff08;如高光谱、多光谱成像数据&#xff09;至较低的通道数&#xff0c;对提高深度学习&#xff08;DL&#xff09;模型的训练速度和预测至关重要。本文主要展示利用PCA降维结合weight-average的图像融合方法。文章主要参…

leetcode第206题反转链表❤

一&#xff1a;题目&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网…

【OpenCV】在MacOS上源码编译OpenCV

在MacOS上源码编译OpenCV 1. 下载项目源码2. 创建CMake编译文件3. 编译安装4. 案例测试5. 总结 前言 在做视觉任务时&#xff0c;我们经常会用到开源视觉库OpenCV&#xff0c;OpenCV是一个基于Apache2.0许可&#xff08;开源&#xff09;发行的跨平台计算机视觉和机器学习软件…

js中函数动态调用

文章目录 一、场景二、方法2.1、动态函数2.2、eval()函数 三、最后 一、场景 在JS开发中&#xff0c;例如有些场景下&#xff0c;后端要求一个功能要请求不同的接口&#xff0c;但是传参及后续逻辑其实都是一样的&#xff0c;有些同学可能会想到在接口url处统一处理就好&#…

在 docker 容器中配置双网卡,解决通讯的问题

目录 1. 查看当前网络信息 2. 创建自定义网络 3. 查看网卡信息 4. 建立双网卡模式 5. 查看容器的网络 6. 从双网卡中删除默认网卡 已经创建好了的 Docker 容器&#xff0c;要修改它的IP比较麻烦&#xff0c;网上找了几种不同的方法&#xff0c;经过试验都没有成功&…