《Linux C编程实战》笔记:文件读写

Linux c下文件读写可用creat,open,close,read,write,lseek等函数。对于跨平台的程序还是用C标准库的fopen等。

open

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open (const char *pathname, int flags);
int open(const char *pathname,int flags, mode_t mode);

第一个参数是文件名,第二个参数是打开文件的方式

flags:

  1. O_RDONLY: 只读打开文件。
    以只读方式打开文件。

  2. O_WRONLY: 只写打开文件。
    以只写方式打开文件。

  3. O_RDWR: 读写方式打开文件。
    以读写方式打开文件。

  4. O_CREAT: 如果文件不存在,则创建文件。
    如果文件不存在,则创建文件。

  5. O_EXCL: 与O_CREAT一起使用,用于确保文件是新创建的。如果文件已存在且O_EXCL标志被指定,则open会失败。

  6. O_TRUNC: 如果文件存在且以写方式打开,则将文件截断为零长度。

  7. O_APPEND: 在文件末尾追加数据。

  8. O_NONBLOCK: 非阻塞模式。使用此标志,文件描述符将以非阻塞方式打开,读写操作不会阻塞进程。

  9. O_SYNC: 打开文件以同步写入方式。所有写入操作将立即写入物理介质。

前三个方式互斥,但可以与后面的进行或运算

mode 参数用于指定新文件的权限,它是一个三位的八进制数字,每一位表示不同的权限。这个参数通常与 O_CREAT 标志一起使用,以确保新文件被创建时有适当的权限设置。

以下是一些常见的权限位和它们的含义:

  1. S_IRUSR (0400): 用户(文件所有者)具有读权限。 中文:用户(文件所有者)具有读权限。

  2. S_IWUSR (0200): 用户具有写权限。

  3. S_IXUSR (0100): 用户具有执行权限。 

  4. S_IRGRP (0040): 组具有读权限。 

  5. S_IWGRP (0020): 组具有写权限。

  6. S_IXGRP (0010): 组具有执行权限。 

  7. S_IROTH (0004): 其他用户具有读权限。

  8. S_IWOTH (0002): 其他用户具有写权限。

  9. S_IXOTH (0001): 其他用户具有执行权限。

这些权限位可以通过按位或运算组合在一起,以设置文件的权限。例如,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 表示文件所有者具有读写权限,而组和其他用户只有读权限。

mode 参数中,这些权限位可以使用宏来表示,如 S_IRWXU 表示用户有读、写和执行权限。这有助于提高代码的可读性。

成功调用open会返回一个文件描述符,若有错误则返回-1,并把错位代码赋给errno。

creat

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat (const char *pathname, mode t mode);

creat 系统调用用于以只写方式打开文件,并在文件不存在时创建它。它相当于使用 open 调用,其中包括了 O_WRONLY | O_CREAT | O_TRUNC 标志。

  • pathname:包含文件路径的字符串。
  • mode:文件权限位(类似于 open 系统调用中的 mode 参数)。

返回值

成功时,creat 返回一个非负整数,它是与新创建或已打开文件关联的文件描述符。失败时返回-1,并设置 errno 以指示错误。

close

#include <unistd.h>
int close(int fd);

close 函数关闭一个先前由 opencreat 打开的文件描述符。关闭文件描述符后,它将不再指向任何文件,且不能再用于读取或写入。

  • fd:要关闭的文件描述符。

示例程序1

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<cstdlib>
int main(){int fd;//打开文件,文件不存在自动创建,文件存在则出错,文件所有者有读写权限if((fd=open("example_62.c",O_CREAT|O_EXCL,S_IRUSR|S_IWUSR))==-1){perror("open");//printf("open:%s  with errno:%d\n",strerror(errno),errno);exit(1);}else{printf("create file success\n");}close(fd);return 0;
}

第一次运行

成功创建。再一次运行呢?

错误,因为O_EXCL被设置。

顺便,了解一下上面头文件的作用

  1. sys/types.h

    • 包含各种基本数据类型的定义,如 size_tpid_t
    • 通常用于定义与系统相关的数据类型。
  2. sys/stat.h

    • 包含文件状态信息的结构体定义,如 struct stat
    • 提供了文件权限位的宏定义,如 S_IRUSRS_IWGRP
    • 用于获取和设置文件的状态信息。
  3. fcntl.h

    • 定义了文件控制操作所需的常量,如 O_RDONLYO_WRONLY
    • 提供了 open 函数和一些文件控制操作函数的声明。
    • 用于打开、关闭、复制和其他文件操作。
  4. unistd.h

    • 提供了 POSIX 系统调用的声明,如 readwriteclose
    • 包含一些常用的符号常量,如 STDIN_FILENOSTDOUT_FILENOSTDERR_FILENO
    • 用于实现对文件描述符的基本 I/O 操作。
  5. errno.h

    • 定义了 errno 全局变量,该变量在系统调用失败时被设置为指示错误的整数值。
    • 包含一些与错误码相关的宏定义,如 EACCESEINVAL
    • 用于检查和处理系统调用产生的错误。

这些头文件通常用于系统级编程,允许开发者使用系统调用和低级 I/O 操作。在编写需要直接与文件系统、进程控制等打交道的程序时,这些头文件是必需的。

read

#include <unistd.h>
ssize_t read(int fd, void *buf, sizet count);
  1. fd (file descriptor)

    • 文件描述符,它是一个非负整数,用于标识已打开文件或 I/O 设备。通常由 open 函数返回。
    • 表示从哪个文件或设备读取数据。
  2. buf (buffer)

    • 指向用于存放读取数据的缓冲区的指针。
    • buf 必须是一个有效的内存地址,足够大以容纳要读取的数据。
  3. count (size_t)

    • 期望读取的字节数。
    • count 参数指定了 buf 缓冲区的大小,即期望从文件中读取的字节数。
  4. 返回值 (ssize_t)

    • 返回值是已经成功读取的字节数。如果到达文件末尾(EOF),返回值为 0。
    • 如果出现错误,返回值为 -1,并且 errno 被设置以指示错误的原因。

最好能将返回值与参数count进行比较,若比count少,则可能是读到文件尾或读取被中断。

读写指针会跟着移动

wtire

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

    • 文件描述符,是一个非负整数,用于标识已打开文件或 I/O 设备。通常由 open 函数返回。
    • 表示写入数据的目标文件或设备。
  2. buf (buffer):

    • 指向包含待写入数据的缓冲区的指针。
    • buf 必须是一个有效的内存地址,包含要写入的数据。
  3. count (size_t):

    • 要写入的字节数。
    • count 参数指定了 buf 缓冲区中的数据大小,即要写入的字节数。
  4. 返回值 (ssize_t):

    • 返回已经成功写入的字节数。如果写入失败,返回值为 -1,并且 errno 被设置以指示错误的原因。

lseek

用来移动文件读写指针的位置

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

    • 文件描述符,是一个非负整数,用于标识已打开文件或 I/O 设备。通常由 open 函数返回。
    • 表示要操作的文件。
  2. offset (off_t):

    • 偏移量,是一个有符号整数,指定了文件偏移的目标位置。
    • 如果 whence 参数是 SEEK_SET,则 offset 表示从文件开始处的偏移量;如果是 SEEK_CUR,则 offset 表示从当前文件偏移处的偏移量;如果是 SEEK_END,则 offset 表示从文件末尾处的偏移量。
  3. whence (int):

    • 定位基准,指定了偏移量的计算方式。可以是 SEEK_SETSEEK_CURSEEK_END
    • SEEK_SET 表示从文件开始处计算偏移,SEEK_CUR 表示从当前位置计算偏移,SEEK_END 表示从文件末尾处计算偏移。
  4. 返回值 (off_t):

    • 返回新的读写指针距离文件开始处的偏移量。如果出现错误,返回值为 -1,并且 errno 被设置以指示错误的原因。

示例程序2

演示文件读写和文件读写指针的移动操作过程

#include<iostream>
#include<cstring>
#include <cstdio>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cerrno>
using namespace std;
//自定义的错误处理函数
void my_err(const char *err_string,int line){fprintf(stderr,"line:%d ",line);perror(err_string);exit(1);
}
//自定义的读数据函数
int my_read(int fd){int len;int ret;int i;char read_buf[64];//获得文件长度if(lseek(fd,0,SEEK_END)==-1)//首先偏移指针移动到文件末尾my_err("lseek",__LINE__);if((len=lseek(fd,0,SEEK_CUR))==-1)//函数返回距离开头的偏移量大小,因为现在指针已经在末尾,SEEK_CUR==SEEK_END,这样函数返回的偏移量就是文件的长度my_err("lseek",__LINE__);if((lseek(fd,0,SEEK_SET))==-1)//把偏移指针回到开头,不会影响后续的读写my_err("lseek",__LINE__);printf("len:%d\n",len);//读if((ret=read(fd,read_buf,len))<0)my_err("read",__LINE__);//读操作出错for(i=0;i<len;i++)printf("%c",read_buf[i]);//打印读取的内容printf("\n");return ret;
}
int main(){int fd;char write_buf[32]="hello world";//可读可写方式创建,若文件存在则覆盖if((fd=open("example_63.c",O_RDWR|O_CREAT|O_TRUNC,S_IRWXU))==-1)//先打开文件,获得文件描述符my_err("open",__LINE__);else printf("create file success\n");//写if(write(fd,write_buf,strlen(write_buf))!=strlen(write_buf))//判断写是否完全成功my_err("write",__LINE__);my_read(fd);//再读printf("/*------------*/\n");if(lseek(fd,10,SEEK_END)==-1)//往文件末尾再向后移动10字节my_err("lseek",__LINE__);if(write(fd,write_buf,strlen(write_buf))!=strlen(write_buf))//在文件末尾后10字节处开始再写my_err("write",__LINE__);my_read(fd);//读close(fd);return 0;
}

运行结果

但是不完全对,运行下面命令发现

具体解释而言

if(lseek(fd,10,SEEK_END)==-1)//往文件末尾再向后移动10字节my_err("lseek",__LINE__);

文件读写指针移动到EOF后10字节再写,中间的间隔以'\0'填充,但是'\0'在C语言打印为空,所以程序打印的结果和查看文件内容的结果不尽相同。

顺便了解

od 命令是一个用于显示文件内容的 Linux/Unix 命令。它以八进制或十六进制的形式显示文件的内容,也可以按字节、短整数、长整数等格式显示。

以下是 od 命令的基本语法:

od [options] [file]

其中,file 是要查看内容的文件名。

一些常用的选项包括:

  • -a:以字符和八进制的形式显示文件内容。
  • -t:指定显示的格式,比如 -to2 表示以八进制短整数的形式显示。
  • -x:以十六进制形式显示文件内容。
  • -c:以字符形式显示文件内容。

perror 函数是一个用于打印与当前 errno 值相关联的错误消息的标准C库函数。它的原型如下:

#include <stdio.h>

void perror(const char *s);

其中:

  • s 是一个用户自定义的字符串,用于在错误消息前输出一些额外的信息。通常,这个字符串是简短的描述性文字,以帮助理解错误的上下文。

perror 函数的作用是将 errno 的当前值转换为对应的错误消息,并将该消息输出到标准错误流(stderr)。perror 在输出错误消息后,会加上冒号和空格,然后输出 s 指定的字符串,最后再输出一个换行符。

比如

#include <stdio.h>
#include <errno.h>int main() {FILE *file = fopen("nonexistent_file.txt", "r");if (file == NULL) {perror("Error opening file");}return 0;
}

在上面的例子中,如果 fopen 失败(比如因为文件不存在),perror 将打印类似于以下的消息:

Error opening file: No such file or directory

fprintf(stderr, "line:%d ", line);

这行代码使用了 fprintf 函数来将格式化的输出发送到标准错误流(stderr)。下面是对该代码片段的解释:

  • fprintf 函数

    • fprintf 是标准C库提供的函数,用于将格式化的数据写入流中。
    • 它的原型为:int fprintf(FILE *stream, const char *format, ...);
    • stream 参数指定要写入的流,可以是 stdout(标准输出)或 stderr(标准错误)等。
    • format 参数是一个字符串,指定了输出的格式,类似于 printf 中的格式字符串。
    • 后续的参数是要插入到格式字符串中的值。
  • stderr

    • stderr 是标准错误流,与 stdout(标准输出流)类似,但通常用于输出错误信息。
    • 在C语言中,stderr 是一个预定义的文件指针,表示指向标准错误流的指针。
    • 输出到 stderr 通常用于报告程序运行中的错误和警告,而不是正常的输出。

fprintf(stderr, "line:%d ", line); 会将输出发送到标准错误流 (stderr),而在命令行中运行程序时,这些错误消息会在命令行终端上显示。

在Linux或Unix系统中,标准输出 (stdout) 通常与命令行终端关联,而标准错误 (stderr) 也会显示在相同的终端上。这意味着通过 fprintf(stderr, ...) 输出的内容将显示在运行程序的命令行终端上,而不是被重定向到文件或其他位置。

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

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

相关文章

Linux——进程创建与进程终止

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、进程创建1、fork函数初识2、fork函数返回值3、写时拷贝4、fork常规用法5、fork调用失败的…

【产品经理】产品增效项目落地,项目反哺产品成长

产品和项目是相辅相成的关系&#xff0c;产品的规范、成熟&#xff0c;为项目的快速落地提供支撑&#xff0c;项目的落地反哺产品&#xff0c;促进产品的成长成熟。 软件工程的初期是&#xff0c;我们需要什么&#xff0c;就立项项目&#xff0c;通过项目实现需要。 随着项目的…

什么是前端国际化(internationalization)和本地化(localization)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

Python+Yolov8+onnx-deepsort方法物体人流量识别统计

程序示例精选 PythonYolov8onnx-deepsort方法物体人流量识别统计 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonYolov8onnx-deepsort方法物体人流量识别统计》编写代码&#xff0c;…

Oracle(2-15)RMAN Incomplete Recovery

文章目录 一、基础知识1、The Procedure 不完全恢复步骤2、UNTIL TIME Example 基于时间的恢复3、UNTIL SEOUENCE Example 基于序列的恢复4、什么是RMAN的不完全恢复 二、基础操作1、不完全恢复准备工作2、不完全恢复开始恢复 RMAN Incomplete Recovery RMAN的不完全恢复 目标&…

翻译: 工作使用ChatGPT的例子 Day-to-day usage of web UI LLMs

本周&#xff0c;我们将首先探讨生成型AI在商业中的作用&#xff0c;然后是其对社会的影响&#xff0c;例如对就业的影响。我们将从探讨如何在日常工作中使用网络用户界面访问生成型AI开始&#xff0c;然后再看看如何系统地分析一个企业&#xff0c;以识别使用生成型AI增强或自…

二叉搜索树的实现

本文旨在讲解如何编写一颗二叉搜索树&#xff0c;包括基本的增删查改的操作。 目录 一、二叉搜索树的概念 ​编辑二、二叉搜索树的编写 2.1节点的编写 2.2节点的插入 2.3节点的查找 2.4节点的删除 三、二叉搜索树的应用 四、 二叉搜索树的性能分析 五、完整代码 一、…

labelme标注json文件检查标注标签(修改imageWidth,imagePath,imageHeight)

# !/usr/bin/env python # -*- encoding: utf-8 -*- #---wzhimport os import json# 这里写你自己的存放照片和json文件的路径 json_dir =rC:\Users\Lenovo\Desktop\json3 json_files = os.listdir(json_dir

Java解决最小路径和

Java解决最小路径和 01 题目 给定一个包含非负整数的 *m* x *n* 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。 **说明&#xff1a;**每次只能向下或者向右移动一步。 示例 1&#xff1a; 输入&#xff1a;grid [[1,3…

Vue3报错: ‘defineProps‘ is not defined,解决方法

问题出现: 今天在使用 <script setup>组合式 API 的语法糖的时候&#xff0c;定义defineProps时候报错&#xff1a; ‘defineProps’ is not defined 查了一下资料&#xff0c;这是因为eslint的语法校验导致的问题。 解决方法1&#xff1a; 在项目根目录的文件.eslin…

大模型词向量:解析语义,助你成为沟通达人

文章目录 一、向量二、如何把词转换为向量三、如何把词转换为向量进阶 三、如何让向量具有语义信息 大家好&#xff0c;我是脚丫先生 (o^^o) 在研究大模型的时候&#xff0c;有一篇文章写得非常通俗易懂。 之前在其他地方不是怎么看懂&#xff0c;但是在这里懂了&#x1f604;…

flowable工作流看这一篇就够了(高级篇 下)

目录 三、候选人和候选人组 3.1、候选人 3.1.1、定义流程图 3.1.2、部署和启动流程实例 3.1.3、任务的查询 3.1.4、任务的拾取 3.1.5、任务的归还 3.1.6、任务的交接 3.1.7、任务的完成 3.2、候选人组 3.2.1、管理用户和组 用户管理 Group管理 为用户分配组 3.2…

深入理解网络 I/O:单 Group 混杂模式|多 Group 主从模式

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

Linux 常用的操作命令

我们习惯的使用Windows,安装软件进行使用&#xff0c;比如 WPS&#xff0c;浏览器&#xff0c;一些工具&#xff0c;但是在Linux上就需要用命令去操作&#xff0c;也可以使用像Ubuntu 和 CentOS这类的可视化面板 Linux系统是开源的&#xff0c;所以开发人员可以反复的发现Bug以…

1231. 航班时间(整行字符串输入:getline(cin,line))

题目&#xff1a; 1231. 航班时间 - AcWing题库 输入样例&#xff1a; 3 17:48:19 21:57:24 11:05:18 15:14:23 17:21:07 00:31:46 (1) 23:02:41 16:13:20 (1) 10:19:19 20:41:24 22:19:04 16:41:09 (1)输出样例&#xff1a; 04:09:05 12:10:39 14:22:05 思路&#xff1a; …

selenium 做 Web 自动化,鼠标当然也要自动化!

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

docker安装Prometheus

docker安装Prometheus Docker搭建Prometheus监控系统 环境准备(这里的环境和版本是经过测试没有问题,并不是必须这个版本) 主机名IP配置系统说明localhost随意2核4gCentOS7或者Ubuntu20.0.4docker版本23.0.1或者24.0.5,docker-compose版本1.29 安装Docker Ubuntu20.0.4版本…

STM32——串口

串口发送/接收函数&#xff1a; HAL_UART_Transmit(); 串口发送数据&#xff0c;使用超时管理机制 HAL_UART_Receive(); 串口接收数据&#xff0c;使用超时管理机制 HAL_UART_Transmit_IT(); 串口中断模式发送 HAL_UART_Receive_IT(); 串口中断模式接收 HAL_UART_Tran…

Netty常见的设计模式

简介 设计模式在软件开发中起着至关重要的作用&#xff0c;它们是解决常见问题的经过验证的解决方案。而Netty作为一个优秀的网络应用程序框架&#xff0c;同样也采用了许多设计模式来提供高性能和可扩展性。在本文中&#xff0c;我们将探讨Netty中使用的一些关键设计模式&…

云开发微信小程序实战

随着移动互联网的快速发展&#xff0c;微信小程序作为一种轻量级的应用程序&#xff0c;逐渐成为了企业开展业务和提升用户体验的重要工具。而云开发则为企业提供了高效、安全、可靠的后台服务&#xff0c;使得小程序的开发和维护更加便捷。本文将详细介绍如何使用微信小程序与…