linux 应用开发笔记---【I/O文件/基础篇 】

文章笔记来自于【速学Linux】手把手教你学嵌入式Linux C应用编程_哔哩哔哩_bilibili

一,什么是linux应用程序

1.运行在linux操作系统用户空间的程序

2.内核程序运行在内核空间,应用程序运行在用户空间

在终端执行的命令ls,ps。。。。。。都是运行在用户空间

3.内核空间和用户空间

二,应用编程与裸机编程、驱动编程有什么区别?

三,如何编写linux应用程序

1.系统调用  【linux操作系统向应用层提供的接口,system call ,是linux 应用层进入内核空间的入口】

2.库函数:标准c库函数  【对系统调用的封装】

3.不要局限于编程语言 

四,文件I/O基础

1.什么是文件I/O ?   【对文件的输入和输出操作,也就是对文件的读/写操作】

2.文件描述符

这相当于是每次打开一个文件,每个文件会分配一个文件描述符【分配一个没有被使用的最小非负整数作为文件描述符】,相当于这个文件的标签一下,所有执行 IO 操作的系统调用都是通过文件描述符来索引到对应的文件,一个进程最多可以打开 1024 个文件,当文件被关闭时,对应的文件描述符会被释放,释放之后也就成为了一个没有被使用的文件描述符了

3.打开/创建文件:open()函数

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname 字符串类型,用于标识需要打开或创建的文件,可以包含路径(绝对路径或相对路径)信息,譬如:"./src_file" (当前目录下的 src_file 文件)、 "/home/dengtao/hello.c" 等;如果 pathname 是一个符号链接,会对其进行解引用
flags 调用 open 函数时需要提供的标志,包括文件访问模式标志以及其它文件相关标志,这些标志使
用宏定义进行描述

mode 此参数用于指定新建文件的访问权限
Linux 中 已经定义好的宏,不同的宏定义表示不同的权限

 

4.写文件:write()函数

ssize_t write(int fd, const void *buf, size_t count);
fd 文件描述符。关于文件描述符,前面已经给大家进行了简单地讲解,这里不再重述!我们需要将进
行写操作的文件所对应的文件描述符传递给 write 函数。
buf 指定写入数据对应的缓冲区。
count 指定写入的字节数。
返回值: 如果成功将返回写入的字节数( 0 表示未写入任何字节),如果此数字小于 count 参数,这不
是错误,譬如磁盘空间已满,可能会发生这种情况;如果写入出错,则返回 -1
读文件和写文件存在一个读写位置【读写指针】,假设初始打开的文件才开始是在0的位置,当写入100字节,指针往后移动100字节,且 读写指针是共用指针,然后就会从100字节出开始读取
5.读文件: read()函数
ssize_t read(int fd, void *buf, size_t count);
fd 文件描述符。与 write 函数的 fd 参数意义相同。
buf 指定用于存储读取数据的缓冲区。
count 指定需要读取的字节数。
返回值: 如果读取成功将返回读取到的字节数,实际读取到的字节数可能会小于 count 参数指定的字节
数,也有可能会为 0 ,譬如进行读操作时,当前文件位置偏移量已经到了文件末尾。实际读取到的字节数少
于要求读取的字节数,譬如在到达文件末尾之前有 30 个字节数据,而要求读取 100 个字节,则 read 读取成
功只能返回 30;而下一次再调用 read 读,它将返回 0 (文件末尾)

6. 关闭文件: close()函数

int close(int fd);
fd 文件描述符,需要关闭的文件所对应的文件描述符。
返回值: 如果成功返回 0 ,如果失败则返回 -1

学习示例:

1.打开文件,写入内容

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{int fd;int ret;fd = open("./test.txt",O_WRONLY | O_CREAT | O_EXCL,0644);if(-1 == fd){printf("open error");return 1;}printf("open ok\r\n");ret = write(fd, "Hello world",11);if(-1 == ret){printf("write error\r\n");close(fd);return 1;}printf("write %d Bytes OK",ret);close(fd);return 0;
}

 运行结果:

 2.读取文件内容

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>int main()
{int fd;char buf[125] = {0};int ret;fd = open("./test.txt",O_RDONLY);   if(-1 == fd){printf("open error");}printf("open ok");ret = read(fd, buf, 11);if(-1 == ret){printf("read error\r\n");close(fd);return 1;}printf("read %d bytes: %s",ret,buf);close(fd);return 0;
}

运行结果:

7.调整读写位置偏移:lseek()函数

off_t lseek(int fd, off_t offset, int whence);
fd 文件描述符。
offset 偏移量,以字节为单位。
whence 用于定义参数 offset 偏移量对应的参考值,该参数为下列其中一种(宏定义):
SEEK_SET :读写偏移量将指向 offset 字节位置处(从文件头部开始算
SEEK_CUR :读写偏移量将指向当前位置偏移量 + offset 字节位置处, offset 可以为正、也可以为
负,如果是正数表示往后偏移,如果是负数则表示往前偏移;
SEEK_END :读写偏移量将指向文件末尾 + offset 字节位置处,同样 offset 可以为正、也可以为负,
如果是正数表示往后偏移、如果是负数则表示往前偏移。

 五,深入探究文件I/O

1.linux系统如何进行文件管理?

文件储存在硬盘上,硬盘的最小存储单位叫做“扇区”(Sector),每个扇区储存 512 字节(相当于 0.5KB),操作系统读取硬盘的时候,以“块”为单位进行文件读取。【“块”的大小,最常
见的是 4KB,即连续八个 sector 组成一个 block

静态文件:文件存放在磁盘内叫做静态文件

inode: 指向文件存放在磁盘的位置

pcb: 进程控制块,管理该进程,譬如用于记录进程的状态信息、运行特征,

 2.错误处理

1.errno

2.strerror函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{int fd1;fd1 = open("./test111.c",O_RDONLY);if(-1 == fd1){printf("%s\n", strerror(errno));return -1;}return 0;
}

 运行结果:

3.perror:可以加入自己的打印信息

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{int fd1;fd1 = open("./test111.c",O_RDONLY);if(-1 == fd1){perror("open error");return -1;}return 0;
}

运行结果

 3.空洞文件

概念:当一个文件本身只有4k的大小,但是当前的通过lseek从文件头部偏移6000个字节,开始写入内容,导致4096-6000字节间没有内容,出现了“空洞”,也就是空洞文件

使用场景:一个文件可以从不同的地址开始写入,不再是单线程从头开始写入,多个线程同时写入,利用了多线程的优势

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
static unsigned char buf[4096];
int main(void)
{int fd;int ret;fd = open("./test.txt",O_WRONLY | O_CREAT | O_EXCL,0644);if(-1 == fd){perror("open error");return 1;        }ret = lseek(fd, 4096, SEEK_SET);if(-1 == ret){perror("lseek error");close(fd);return 1;}ret = write(fd, buf, 4096);if(-1 == ret){printf("write error");close(fd);return 1;}close(fd);return 0;}

运行结果:

ls 命令:查看到的大小是文件的逻辑大小   
du 命令:查看到的大小是文件实际占用存储块的大小

4.O_TRUINC和O_APPEND

O_TRUINC将文件原本的内容全部丢弃,文件大小变为 0
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{int fd;fd = open("./test.txt",O_WRONLY | O_TRUNC);if(-1 == fd){perror("open error");close(fd);return 1;        }    close(fd);return 0;
}

运行结果:

O_APPEND当每次使用 write()函数对文件进行写操作时,都会自动把文件当前位置偏移量移动到文件末尾
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{int fd;int ret;fd = open("./test.txt",O_WRONLY | O_APPEND);if(-1 == fd){perror("open error");close(fd);return 1;        }    ret = write(fd,"hello world",11);if(-1 == ret){perror("write error");close(fd);return 1;}close(fd);return 0;
}

运行结果:

open可以多次打开一个文件,产生多个文件描述符,也就是存在多个文件表,,但是都指向同一个文件,但是只能产生一个动态文件,以及同一个inode。对于打开的每一个fd.都要依次关闭。

5.文件描述符的复制

int dup(int oldfd);                           复制文件描述符

int dup2(int oldfd, int newfd);        文件描述符的数可以自行决定

新的文件描述符和旧的指向同一个文件表,去完成任何操作

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{int fd1, fd2;int ret;fd1 = open("./test_file", O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);if (-1 == fd1) {perror("open error");exit(-1);}/* 复制文件描述符 */fd2 = dup2(fd1, 100);if (-1 == fd2) {perror("dup error");ret = -1;goto err1;}printf("fd1: %d\nfd2: %d\n", fd1, fd2);ret = 0;close(fd2);
err1:/* 关闭文件 */close(fd1);exit(ret);
}

运行结果

6.文件共享

概念:同一个文件(譬如磁盘上的同一个文件,对应同一个 inode)被多个独立的读写体同时进行 IO 操作

常见的三种文件共享的实现方式

(1)同一个进程中多次调用open函数打开同一个文件,多个文件描述符指向不同的文件表,但是多个文件表中的inode指针指向inode节点

(2)不同的进程分别打开同一个文件

(3)同一个进程中通过dup(dup2)函数对文件描述符进行复制 

 7.原子操作与竞争冒险

竞争冒险:进程获得cpu的使用权完全是由操作系统决定的,先后顺序是不可预期的

原子操作:多个步骤组成的一个操作,要么不执行,要么必须执行完所有操作,不可以只执行所有步骤的一个子集

(1)O_APPEND 实现原子操作
移动到文件末尾,然后读写文件
(2)pread() 和 pwrite()
移动到偏移位置,然后读写文件

(3) 创建一个文件O_EXCL
先判断是否有文件 然后创建文件

 8.截断文件

ftruncate():使用文件描述符 fd 来指定目标文件大小,目标文件必须具有可写权限

truncate(): 使用 文件路径path 来指定目标文件大小
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{  int fd;int ret;fd = open("./test.txt", O_RDONLY | O_WRONLY);if(-1 == fd){perror("open error");return 1;        }ret = ftruncate(fd, 4096);if(ret == -1){perror("sss");return 1;}close(fd);return 0;
}

运行结果:

9.fcntl和ioctl函数

fcntl()函数():对文件描述符做一系列的控制操作

int fcntl(int fd, int cmd, ... /* arg */ )
cmd 命令集:
复制文件描述符( cmd=F_DUPFD cmd=F_DUPFD_CLOEXEC)
获取 / 设置文件描述符标志( cmd=F_GETFD cmd=F_SETFD
获取 / 设置文件状态标志( cmd=F_GETFL cmd=F_SETFL
获取 / 设置异步 IO 所有权( cmd=F_GETOWN cmd=F_SETOWN
获取 / 设置记录锁( cmd=F_GETLK cmd=F_SETLK

ioctl()函数:是一个文件 IO 操作的杂物箱,可以处理的事情非常杂、不统一

int ioctl(int fd, unsigned long request, ...);

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

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

相关文章

【MySQL的DQL查询语句】

MySQL的DQL查询语句-----在Navicat下 将学生表导入Navicat中查询语句查询一整张表查询年龄大于22年龄大于22的女生查找文科的学生查找六班的学生计算学生的总分 &#xff08;group by&#xff09;合并两表 &#xff08;join on xxxx&#xff09;合并两张表 并求总分先合并在聚合…

Java+springboot+avue医院绩效考核系统源码支持二次开发

公立医院改革要求建立公立医疗卫生机构绩效考核体系&#xff0c;借助绩效考核来引导各级公立医院把社会效益摆在首位&#xff0c;提高医疗服务质量&#xff0c;规范医疗服务行为&#xff0c;加强医院内部管理&#xff0c;促进医院高质量发展 医院绩效考核系统&#xff0c;建立以…

python 运用pandas 库处理excel 表格数据

文章目录 读取文件查看数据数据选择数据筛选创建新列计算并总结数据分组统计 读取文件 Pandas 是一个强大的数据分析库&#xff0c;它提供了丰富的数据结构和数据分析工具&#xff0c;其中之一是用于读取不同格式文件的 read_* 函数系列。以下是一个简单介绍如何使用 Pandas 读…

Siemens-NXUG二次开发-C/C++/Python环境配置[20231204]

Siemens-NXUG二次开发-C/C/Python运行方式[20231204] 1.NX/UG C/C/Python API官方开发文档2.运行方式2.1内部模式2.2 外部模式2.3 许可证书服务器启动 3.C/C环境配置4.Python环境配置5.第三方环境配置 1.NX/UG C/C/Python API官方开发文档 西门子NX/UG Python api开发文档&…

Spring学习笔记:Day2

昨天定的学习计划发现通过文心4.0来实现不靠谱&#xff0c;坑太多&#xff0c;今天开始跟随B站进行学习&#xff0c;争取10-15天学习一遍&#xff0c;冲啊&#xff01; 地址&#xff1a;001-课程介绍_哔哩哔哩_bilibili 今日规划&#xff1a; pt 001 - pt 018&#xff0c;提到…

小心处理 C++ 静态变量中的陷阱

小心处理 C 静态变量中的陷阱 函数中的 static 变量 static 变量的作用 C 中 static 关键字的最后一个用途是在函数内创建局部变量&#xff0c;这些变量在其作用域内退出和进入时保持其值。函数内的 static 变量类似于只能从该函数访问的全局变量。static 变量的一个常见用途…

【UGUI】实现背包的常用操作

1. 添加物品 首先&#xff0c;你需要一个包含物品信息的类&#xff0c;比如 InventoryItem&#xff1a; using UnityEngine;[CreateAssetMenu(fileName "NewInventoryItem", menuName "Inventory/Item")] public class InventoryItem : ScriptableObje…

网工学习7-配置 GVRP 协议

7.1GARP概述 GARP(Generic Attribute Registration Protocol)是通用属性注册协议的应用&#xff0c;提供 802.1Q 兼容的 VLAN 裁剪 VLAN pruning 功能和在 802.1Q 干线端口 trunk port 上建立动态 VLAN 的功能。 GARP 作为一个属性注册协议的载体&#xff0c;可以用来传播属性…

游泳馆会员服务预约管理系统预约小程序效果如何

游泳馆在各地每天都有大量用户前往&#xff0c;夏季室外、冬季室内也是学习游泳技术和休闲娱乐的好地方&#xff0c;而消费者大多是年轻人和家长带的孩子&#xff0c;这部分群体更显年轻化&#xff0c;因此在如今互联网环境下&#xff0c;传统商家需要进一步赋能客户消费路径。…

【Vue】Vue CLI 脚手架(Vue Command Line Interface)安装教程(通过npm)

前言 Vue CLI&#xff08;Vue Command Line Interface&#xff09;是一个基于Vue.js的官方脚手架工具&#xff0c;用于快速搭建和管理Vue.js项目。它提供了一套完整的开发工具和配置&#xff0c;包括项目初始化、开发服务器、热重载、构建和打包等功能。 Vue CLI使用了Webpac…

自动驾驶学习笔记(十三)——感知基础

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo Beta宣讲和线下沙龙》免费报名—>传送门 文章目录 前言 传感器 测距原理 坐标系 标定 同…

2023/12/3总结

RabbitMq 消息队列 下载地址RabbitMQ: easy to use, flexible messaging and streaming — RabbitMQ 使用详情RabbitMQ使用教程(超详细)-CSDN博客 实现延迟队列&#xff08;为了实现订单15分钟后修改状态&#xff09; 1 死信队列 当一个队列中的消息满足下列情况之一时&…

【risc-v】易灵思efinix FPGA riscv 时钟配置的一些总结

系列文章目录 分享一些fpga内使用riscv软核的经验&#xff0c;共大家参考。后续内容比较多&#xff0c;会做成一个系列。 本系列会覆盖以下FPGA厂商 易灵思 efinix 赛灵思 xilinx 阿尔特拉 Altera 本文内容隶属于【易灵思efinix】系列。 文章目录 系列文章目录前言一、pan…

为何要3次握手?TCP协议的稳定性保障机制

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

操作系统·存储器管理

根据冯诺依曼原理&#xff0c;程序必须先存储在内存中&#xff0c;才可以执行。 在多道程序并发执行的系统存储器管理非常重要。 5.1 存储器管理的功能 5.1.1 主存分配与回收 要完成内存的分配和回收工作&#xff0c;要求设计者选择和确定几种策略和结构&#xff1a; 1.调入…

STM32F407-14.3.10-01PWM模式

PWM 模式 脉冲宽度调制模式可以生成一个信号&#xff0c;该信号频率由 TIMx_ARR⑩ 寄存器值决定&#xff0c;其占空比由 TIMx_CCRx⑤ 寄存器值决定。 通过向 TIMx_CCMRx 寄存器中的 OCxM⑰ 位写入 110 &#xff08;PWM 模式 1&#xff09;或 111 &#xff08;PWM 模式 2&#…

SpringCloud简介和用处

Spring Cloud是一套基于Spring Boot的微服务框架&#xff0c;它旨在提供一种快速构建分布式系统的方法。它可以帮助开发人员构建具有高可用性、可扩展性和容错性的微服务&#xff0c;并通过Spring Boot的开发工具和库提供强大的支持。 一、简介 Spring Cloud是Spring家族中的一…

React如何像Vue一样将css和js写在同一文件

如果想在React中想要像Vue一样把css和js写到一个文件中&#xff0c;可以使用CSS-in-JS。 使用CSS-in-JS 下载 npm i styled-components使用 就像写scss一样&#xff0c;不过需要声明元素的类型 基本语法及展示如下&#xff0c; import styled from "styled-component…

周周清(1)

项目进度&#xff1a; 最近一直在搭建环境&#xff0c;都没写什么&#xff1a;登陆页面采用登陆注册在同一个界面&#xff0c;用v-if进行渲染&#xff0c;并且借助validation插件中的yup神器进行校验&#xff0c; <script setup> // import { ref } from vue import * …

Qt配置OpenCV(MSVC编译)

目录 1.准备工具 1.1 Qt&#xff1a;5.14.2 64位 1.2 Opencv&#xff1a;4.6.0 1.3 Visual Studio 2017 2. QtMSVC开发环境搭建 3. 配置环境变量 3.1 Opencv环境变量配置 4. Qt 代码测试 1.准备工具 1.1 Qt&#xff1a;5.14.2 64位 1.2 Opencv&#xff1a;4.6.0 官…