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

news2024/11/15 23:21:39

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.coloradmin.cn/o/1315355.html

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

相关文章

【️什么是分布式系统的一致性 ?】

&#x1f60a;引言 &#x1f396;️本篇博文约8000字&#xff0c;阅读大约30分钟&#xff0c;亲爱的读者&#xff0c;如果本博文对您有帮助&#xff0c;欢迎点赞关注&#xff01;&#x1f60a;&#x1f60a;&#x1f60a; &#x1f5a5;️什么是分布式系统的一致性 &#xff1f…

基于QTreeWidget实现带Checkbox的多级组织结构选择树

基于QTreeWidget实现带Checkbox的多级组织结构选择树 采用基于QWidgetMingw实现的原生的组织结构树 通过QTreeWidget控件实现的带Checkbox多级组织结构树。 Qt相关系列文章&#xff1a; 一、Qt实现的聊天画面消息气泡 二、基于QTreeWidget实现多级组织结构 三、基于QTreeWidget…

Git忽略已经提交的文件

原理类似于 Android修改submodule的lib包名

FastAdmin后台安装出现2054错误的解决办法

用Navicat修改密码验证方式。MySQL Workbench的Server菜单中的Users and Privileges菜单中似乎不支持此项修改。 修改完毕以后也许会报错&#xff1a; Access denied for user ‘root‘‘localhost‘ (using password: YES) 用以下命令无密进入mysql。 C:\Program Files\MySQ…

基于SSM的校友录设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Qt实现的聊天画面消息气泡

Qt实现的聊天画面消息气泡 采用基于QWidgetMingw实现的原生的消息气泡 通过覆写QWidget::paintEvent(QPaintEvent *event)方法&#xff0c;每当窗口尺寸变化时都会触发paintEvent事件&#xff0c;在覆写QWidget::paintEvent(QPaintEvent *event)方法中重新绘制聊天气泡在QListW…

Unity2023.3(Unity6)版本开始将可以发布WebGPU

翻译一段官网上的话&#xff1a; 利用Unity 2023.3(正式发布时应该称为Unity6)中最新的WebGPU图形API集成&#xff0c;尝试最大限度的提升您的网络游戏的真实感。 通过与谷歌的战略合作&#xff0c;Unity实时3D平台的强大的图形功能现在为图形丰富的网络游戏进行微调&#xff0…

好用的硬盘分区工具,傲梅分区助手 V10.2

傲梅分区助手软件可以帮助用户在硬盘上创建、调整、合并、删除分区&#xff0c;以及管理磁盘空间等操作。它可以帮助你进行硬盘无损分区操作。 支持系统 目前这款软件支持 Windows 7、Windows 8、Windows 10、Windows 11 等个人系统&#xff0c;还支持 Windows 2012/2016/2019…

城市货车通行码二维码解析

目录 说明 界面 下载 城市货车通行码二维码解析 说明 二维码扫描信息为&#xff1a; tmri://12123?ywlx1041&ewmeyJ0eHpiaCI6IjUxMDcwMDAwMDE0MyIsInR4em1jIjoiQeivgSIsImhwemwiOiIwMiIsImhwaG0iOiLlt51CMkwzMjYiLCJrc3JxIjoiMjAyMS0xMS0yOCIsImpzcnEiOiIyMDIyLTEyL…

蓝桥杯专题-真题版含答案-【祖冲之割圆法】【错误票据】【显示为树形】【汉字相乘】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

yolov8实战第一天——yolov8部署并训练自己的数据集(保姆式教程)

​​​​​​yolov8实战第二天——yolov8训练结果分析&#xff08;保姆式解读&#xff09;-CSDN博客 YOLOv8是一种基于深度神经网络的目标检测算法&#xff0c;它是YOLO&#xff08;You Only Look Once&#xff09;系列目标检测算法的最新版本。YOLOv8的主要改进包括&#xf…

5G工业网关视频传输应用

随着科技的不断进步&#xff0c;5G网络技术已经成为了当前最热门的话题之一。而其中一个引人注目的领域就是5G视频传输和5G工业网关应用。在传统网络通信中&#xff0c;由于带宽和延迟的限制&#xff0c;视频传输常常受到限制&#xff0c;而工业网关应用也存在着链路不稳定、数…

Android12-RK3588_s-开机动画

目录 一、实现自定义开机动画 步骤一&#xff1a;准备 bootanimation.zip 步骤二&#xff1a;将 bootanimation.zip 放到 /system/media/bootanimation.zip下 步骤三&#xff1a;重启即可 二、注意事项 2.1 bootanimation.zip 压缩 2.2 bootanimation.zip 存放 2.3 boo…

STM32_启动流程详解

目录标题 前言 启动流程概述复位中断函数详解SystemInit函数详解 __main函数详解 附录 stm32单片机的存储器映像中断向量表的映射 前言 最近在学习IAP远程OTA升级单片机固件程序&#xff0c;发现自己对单片机的启动流程还不是那么了解&#xff0c;就总结整理一下吧。 启动流程…

如何进行Feign的自定义配置

Feign可以支持很多的自定义配置&#xff0c;下列是部分配置信息 类型作用说明Logger.Level修改日志级别配置键&#xff1a;loggerLevel&#xff0c;包含四种不同的级别&#xff1a;NONE、BASIC、HEADERS、FULLClass<Retryer>失败重试机制配置键&#xff1a;retryer&#…

C语言程序_速通_基础_笔记1_备战大一期末考_12.16

1.固定格式 #include<stdio.h>int main(){return 0;} 2.printf 正常输出&#xff1a;printf("XXXXX"); 如果没有任何换行符什么的&#xff0c;输进去多少个printf&#xff0c;就直接连在一起。 \n&#xff0c;换行 \t 空格 3.int float double char flo…

牛客第一期

1.创建动态数组 #include <iostream> using namespace std;int main() {int n; cin>>n; int *pnew int [n]; int i0; for(i0;i<n;i) {*(pi)ni; } int j0; for(j0;j<n;j) {printf("%d ",*(pj)); } } #include<bits/stdc.h> using namespace s…

文件上传自动化测试方案(超详细)

一、概述 【测试地址】&#xff1a;https://pan.baidu.com 【测试工具】&#xff1a;selenium、requests 【脚本语言】&#xff1a;Python 【运行环境】&#xff1a;Windows 百度网盘作为文件存储及分享的平台&#xff0c;核心功能大部分是对文件的操作&#xff0c;如果要…

2024GoCN线下活动全面启动,赠送深圳MeetUp门票

2024年GoCN社区将全面启动一系列令人期待的线下活动---不仅将在北京、上海、深圳、武汉、成都、杭州、广州、西安等地举办 meetup&#xff0c;还将在北京和上海举办 GopherChina 大会。 2024议题征集通道已开启&#xff0c;欢迎各位有实战经验、独特观点的Gopher前来分享~ 2024…

vue中iframe标签跨域通信——父子页面之间传值(解决子页面收不到父页面的值或子页面收到的数据为undefined的问题)

背景 因为本系统需要支持第三方系统页面的嵌入&#xff0c;于是尝试使用iframe标签&#xff0c;进行跨域通信&#xff0c;父子页面相互传值。初始化时&#xff0c;父页面发送数据给子页面&#xff0c;需要在子页面加载完成后发送&#xff0c;不然接收不到数据。父页面直接给子页…