首页 > 系统相关 >嵌入式Linux,文件I/O深入探究,函数相关详解。

嵌入式Linux,文件I/O深入探究,函数相关详解。

时间:2024-12-04 18:29:13浏览次数:9  
标签:文件 函数 int cmd 嵌入式 描述符 详解 Linux include

1. 返回错误处理

在 Linux 系统下对常见的错误做了一个编号,每一个 编号都代表着每一种不同的错误类型,当函数执行发生错误的时候,操作系统会将这个错误所对应的编号 赋值给 errno 变量,每一个进程都维护了自己的 errno 变量,它是程序中的全局变量,该变量用于存储就近发生的函数执行错误编号,也就意味着下一次的错误码会覆盖上一次的错误码。 errno 本质上是一个 int 类型的变量,用于存储错误编号,但是需要注意的是,并不是执行所有的系统调用或C 库函数出错时,操作系统都会设置 errno ,具体的可以查看相关的手册。 以 常用的 open 函数来说,当函数返回错误时会设置 errno。 但是errno只是一个编号:
#include <stdio.h>
#include <errno.h>
int main(void)
{
printf("%d\n", errno);
return 0;
}

打印出来的只是一个数值,那么想知道具体的错误信息就要用到相关的函数。

strerror 函数:该函数可以将对应的 errno 转换成适合我们查看的字符串信息,其函数原型如下:
#include <string.h>
char *strerror(int errnum);
函数参数和返回值解释如下: errnum 错误编号 errno 。 返回值: 对应错误编号的字符串描述信息。 比较简单,可以自行编写一个简单代码测试。 第二个函数是: perror 函数: 调用此函数不需要传入 errno ,函数内部会自己去获取 errno 变量的值,调用此函数会直接将错误提示字符串打印出来,而不是返回字符串,除此之外还可以在输出的错误提示字符串之前加入自己的打印信息,函数原型如下:
#include <stdio.h>
void perror(const char *s);
函数参数和返回值解释如下: s 在错误提示字符串信息之前,可加入自己的打印信息,也可不加,不加则传入空字符串即可。 返回值: void 无返回值。 例子如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int fd;
/* 打开文件 */
fd = open("./test", O_RDONLY);
if (-1 == fd) {
perror("open error");
return -1;
}
close(fd);
return 0;
}

结果:

2. exit_exit_Exit

有过编程经验的朋友都知道使用 return ,一般原则程序执行正常退出 return 0 ,而执行函数出错退出 return -1,在 Linux 系统下,进程正常退出除了可以使用 return 之外,还可以使用 exit() 、 _exit() 以及 _Exit()。 调用 _exit() 函数会 清除其使用的内存空间,并销毁其在内核中的各种数据结构,关闭进程的所有文件描述符,并结束进程、将控制权交给操作系统。_exit() 函数原型如下:
#include <unistd.h>
void _exit(int status);
调用函数需要传入 status 状态标志, 0 表示正常结束、若为其它值则表示程序执行过程中检测到有错误发生。 _exit()和_Exit() 两者等价,用法作用是一样的。

exit() 函数 _exit() 函数都是用来终止进程的, exit() 是一个标准 C 库函数,而 _exit() 和 _Exit() 是系统调用。 执行 exit() 会执行一些清理工作,最后调用 _exit() 函数。 exit() 函数原型如下:
#include <stdlib.h>
void exit(int status);
该函数的用法和_exit()、_Exit()是 一样的。

3. O_APPEND O_TRUNC 

O_TRUNC 这个标志的作用非常简单,如果使用了这个标志,调用 open 函数打开文件的时候会将文件原本的内容全部丢弃,文件大小变为 0。 如果 open 函数携带了 O_APPEND 标志,调用 open 函数打开文件, 当每次使用 write() 函数对文件进行写操作时,都会自动把文件当前位置偏移量移动到文件末尾,从文件末尾开始写入数据,也就是意味着每次写入数据都是从文件末尾开始。 这两个标志的位置和前面所说的open函数其他标志的语法一致,不懂得朋友可以看下面这篇: 文件I/O基础icon-default.png?t=O83Ahttps://blog.csdn.net/YYYYYYJJJJJYYYYY/article/details/144212871 但是两点需要注意: 第一,O_APPEND 标志并不会影响读文件,当读取文件时,O_APPEND 标志并不会影响读位置偏移量,即使使用了 O_APPEND标志,读文件位置偏移量默认情况下依然是文件头。 第二,使用了 O_APPEND 标志,即使是通过 lseek 函数也是无法修改写文件时对应的位置偏移量,写入数据依然是从文件末尾开始,lseek 并不会该变写位置偏移量。

4. 复制文件描述符

dup 函数用于复制文件描述符,此函数原型如下:
#include <unistd.h>
int dup(int oldfd);
函数参数和返回值解释如下: oldfd 需要被复制的文件描述符。 返回值: 成功时将返回一个新的文件描述符,由操作系统分配,分配置原则遵循文件描述符分配原则; 如果复制失败将返回-1 ,并且会设置 errno 值。 dup2 函数:dup 系统调用分配的文件描述符是由系统分配的,遵循文件描述符分配原则,并不能自己指定一个文件描述符,这是 dup 系统调用的一个缺陷;而 dup2 系统调用修复了这个缺陷,可以手动指定文件描述符,而不需要遵循文件描述符分配原则。 dup2 函数原型如下:
#include <unistd.h>
int dup2(int oldfd, int newfd);
函数参数和返回值解释如下: oldfd 需要被复制的文件描述符。 newfd 指定一个文件描述符(需要指定一个当前进程没有使用到的文件描述符)。 返回值: 成功时将返回一个新的文件描述符,也就是手动指定的文件描述符 newfd ;如果复制失败将返回-1 ,并且会设置 errno 值。 注意:复制得到的文件描述符与原文件描述符都指向同一个文件表,所以它们的文件读写偏移量是一样的 。(跟多次open打开同一个文件有所不同)

5. fcntl 函数

fcntl() 函数可以对一个已经打开的文件描述符执行一系列控制操作,譬如复制一个文件描述符(与 dup 、 dup2 作用相同)、获取 / 设置文件描述符标志、获取 / 设置文件状态标志等,类似于一个多功能文件描述符管理工具箱。fcntl() 函数原型如下:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ )
函数参数和返回值含义如下: fd 文件描述符。 cmd 操作命令。此参数表示我们将要对 fd 进行什么操作, cmd 参数支持很多操作命令,cmd 操作命令大致可以分为以下 5 种功能: 1.  复制文件描述符( cmd=F_DUPFD 或 cmd=F_DUPFD_CLOEXEC ); 2.  获取 / 设置文件描述符标志( cmd=F_GETFD 或 cmd=F_SETFD ); 3.  获取 / 设置文件状态标志( cmd=F_GETFL 或 cmd=F_SETFL ); 4.  获取 / 设置异步 IO 所有权( cmd=F_GETOWN 或 cmd=F_SETOWN ); 5.  获取 / 设置记录锁( cmd=F_GETLK 或 cmd=F_SETLK ); fcntl 函数是一个可变参函数,第三个参数需要根据不同的 cmd 来传入对应的实参,配合 cmd 来使用。 返回值: 执行失败情况下,返回 -1 ,并且会设置 errno ;执行成功的情况下,其返回值与 cmd (操作命令)有关,譬如 cmd=F_DUPFD (复制文件描述符)将返回一个新的文件描述符、 cmd=F_GETFD (获取文件描述符标志)将返回文件描述符标志、cmd=F_GETFL (获取文件状态标志)将返回文件状态标志等。 例子: (1) 复制文件描述符 语法举例(实际情况应用即可)
fd2 = fcntl(fd1, F_DUPFD, 0);//复制fd1
要传入第三个参数,第 三个参数用于指出新复制出的文件描述符是一个大于或等于该参数的可用文件描述符(没有使用的文件描述符);如果第三个参数等于一个已经存在的文件描述符,则取一个大于该参数的可用文件描述符。 (2) 获取 / 设置文件状态标志 cmd=F_GETFL 可用于获取文件状态标志, cmd=F_SETFL 可用于设置文件状态标志。 cmd=F_GETFL 时 不需要传入第三个参数,返回值成功表示获取到的文件状态标志;cmd=F_SETFL 时,需要传入第三个参数, 此参数表示需要设置的文件状态标志。 但是文件权限标志( O_RDONLY 、 O_WRONLY 、 O_RDWR )以及文件创建标志( O_CREAT 、 O_EXCL 、 O_NOCTTY 、 O_TRUNC )不能被设置、会被忽略;在 Linux 系统中,只有 O_APPEND 、 O_ASYNC、O_DIRECT 、 O_NOATIME 以及 O_NONBLOCK 这些标志可以被修改
/* 获取文件状态标志 */
 flag = fcntl(fd, F_GETFL);

/* 设置文件状态标志,添加 O_APPEND 标志 */
 ret = fcntl(fd, F_SETFL, flag | O_APPEND);

6. 截断文件

使用系统调用 truncate()或 ftruncate() 可将普通文件截断为指定字节长度,其函数原型如下:
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
这两个函数的区别在于: ftruncate() 使用文件描述符 fd 来指定目标文件,而 truncate() 则直接使用文件路 径 path 来指定目标文件,其功能一样。 这两个函数都可以对文件进行截断操作,将文件截断为参数 length 指定的字节长度。如果文件目前的 大小大于参数 length 所指定的大小,则多余的数据将被丢失。如果文件目前的 大小小于参数 length 所指定的大小,则将其进行扩展,对扩展部分进行读取将得到空字 节"\0" 。 调用这两个函数并不会导致文件读写位置偏移量发生改变,所以截断之后一般需要重新设置文件当前的读写位置偏移量,以免由于之前所指向的位置已经不存在而发生错误。 调用成功返回 0 ,失败将返回 -1 ,并设置 errno 以指示错误原因。 不断学习中,共勉!!!

标签:文件,函数,int,cmd,嵌入式,描述符,详解,Linux,include
From: https://blog.csdn.net/YYYYYYJJJJJYYYYY/article/details/144237624

相关文章

  • 【NZH原创】UNO小游戏(Linux版)
     作者第一次发代码,可能写的不太好,不喜勿喷希望大佬给点意见QWQ这是Linux版的,Window版的过几天发(转向还没写好)#include<bits/stdc++.h>#include<sys/types.h>#include<sys/wait.h>#include<iostream>#include<unistd.h>#include<stdio.h>usingnamespacestd;......
  • 两台linux 服务器如何共享一个磁盘
    两台linux服务器如何共享一个磁盘可以借用NFS工具例如:服务端的系统是centosip为101.0.3.3客户端的系统是ubuntuip为:101.0.3.13如何通过nfs来共享服务端的/data目录?要通过NFS在CentOS和Ubuntu之间共享/data目录,您需要在服务端和客户端上分别进行一些配置。NFS需要开启2049......
  • [Linux网络]TCP和UDP协议的底层理论
    目录一、TCP和UDP协议的简单认识1.传输层协议2.五元组二、UDP协议1.UDP协议格式2.UDP协议的特点3.面向数据报4.UDP传输报文在内核中的管理5.基于UDP协议的应用层协议(部分)三、TCP协议1.发送和接收数据示意图2.TCP协议格式3.确认应答机制和超时重传机制4.发......
  • linux命令——ab
    abApache服务器的性能测试工具安装若系统未安装,使用以下命令安装#Ubuntusudoapt-getinstallapache2-utils#Centosyuminstallhttpd-tools补充说明ab命令 是一个测试你Apachehttp服务器的工具,你可以通过这个工具,指定一个单位时间内向apache发出的请......
  • Java中的“抽象类“详解
    1.抽象类的定义在面向对象的概念中,所有的对象都是通过,类来描述的,但是反过来,不是所有的类都是用来描述对象的,如果一个类中没有包含足够的信息来描述一个具体的对象,这样的类就是抽象类抽象类的概念是比较抽象的,比如现在有一个"父类"是"动物类",继承这个父类的子类中有"......
  • python批量将文件编码格式转换为 UTF8带标签的格式,解决linux环境下中文编码乱码的问题
    指定一个文件夹,遍历文件夹内的文件和子文件夹内的文件,然后识别文件后缀为cpp的文件,通过chardet取检测文件的编码格式,如果不是UTF-8-SIG,则转换为UTF-8-SIGpython脚本格式如下importosimportsysimportcodecsimportchardetdefconvert(filename,out_enc="UTF-8-SIG"):......
  • 「嵌入式系统设计与实现」书评:初步印象
    本文首发于:【「嵌入式系统设计与实现」阅读体验】+初步印象-社区活动专版-电子技术论坛-广受欢迎的专业电子论坛!感谢电子发烧友论坛和电子工业出版社的赠书。我自己从事嵌入式系统的教学工作,也指导过学生参加嵌入式相关的比赛并获得过一些奖项。《嵌入式系统设计与实现......
  • linux开发板更换SD卡,如何确保挂载点固定
    在Linux开发板上更换SD卡时,确保挂载点(mountpoint)固定,你可以通过编辑/etc/fstab文件来实现。/etc/fstab是一个系统启动时挂载文件系统的配置文件。步骤如下: 确定SD卡的分区和类型。使用lsblk或fdisk-l命令查看。 确定你想要挂载的路径,例如/mnt/sdcard。 编辑......
  • 直接删除Linux分区后进入电脑变成grub页面,如何解决
    这个就是Linux没删干净,要把grub删除。我找到两个视频,可以来帮助解决问题。目前我的问题已解决。第一个视频可以暂时从grub页面进入Windows页面,但是不保证之后再开机还是Windows页面。我尝试了一下,如果关机再重启的话还是grub页面而不是Windows页面。【电脑开机报错提示grub,wi......
  • 云桌面技术特点详解
    提到云桌面的架构呢,我们肯定首先想到的是VDI,VDI作为云计算虚拟化技术的一种典型方式,最大的特点就是非常灵活、安全性高,只要有网络,我们就可以访问云桌面但是呢,VDI技术也有相关的一些缺陷,其中最大的缺陷就是它对网络的依赖性非常强,在断网的状态下就无法使用,此外,由于大部分计算......