C/C++ 文件操作基础

2023-05-16

目录

1、文件分类

2、文件的打开与关闭

3、顺序读写文件

4、随机读写文件

5、其他与文件相关的操作


最近看 GNU Radio 源码看到了文件操作的部分,因此记录下学习 C++/C 操作文件的过程。

本文的文件操作是 ANSI C 标准的,在 C/C++ 中都可以使用。

1、文件分类

从数据的组织形式来说,数据文件可以分为 ASCII 文件二进制文件数据在内存(RAM)中是以二进制形式存储的,如果不加处理地输出到外存(ROM)进行文件保存的话,该保存在 ROM 中的文件就是二进制文件。如果要求在 ROM 中以 ASCII 码形式保存的话则需要在存储前进行转换,ASCII 文件又称做文本文件。

就比如内存中有一个 float 类型的浮点数 3.14159 ,如果以二进制形式输出至外存进行存储的话,所占的内存就是 float 固有的 个字节的大小。如果以文本格式进行存储的话,则需要将 3.14259 的每一位数字转换成字符类型(ASCII码)进行存储,这时由于有 7 个字符,因此就需要 个字节的空间存储。

2、文件的打开与关闭

文件的打开与关闭函数分别为 fopen()fclose(),其具体的使用如下:

#include <stdio.h>
FILE *fp;   // 声明文件指针(句柄)
fp = fopen(文件名, 使用文件方式);  // 打开文件
fclose(fp);  // 关闭文件

其中,FILE 为文件类型结构体,定义在 stdio.h 头文件中,用来存放文件名、文件状态、当前位置等信息。一般定义一个 FILE 类型的文件指针,通过指针引用这些 FILE 类型变量更加方便。

fopen 函数的第一个参数是的文件名(字符串类型),是使用绝对路径还是相对路径视实际情况而定,该函数返回一个指向该文件信息区起始地址的指针。第二个参数代表文件的打开方式,是字符串类型的参数,有关该参数的列表如下:

文件使用方式

含义

如果指定的文件不存在

“r”read只读)

为了输入数据,打开已存在的文本文件

报错

“w”write只写)

为了输出数据,打开文本文件

建立新文件

“a”append追加)

文本文件末尾添加数据

报错

rbbinary只读)

为了输入数据,打开已存在二进制文件

报错

wbbinary只写)

为了输出数据,打开二进制文件

建立新文件

“ab”binary追加)

二进制文件末尾添加数据

报错

“r+” / "rw"读写

为了读写数据,打开已存在的文本文件

报错

“w+” / "wr"(读写

为了读写数据,建立新的文本文件

建立新文件

“a+” / "ar"(读写

为了读写数据,打开已存在的文本文件

报错

rb+”读写

为了读写数据,打开已存在的二进制文件

报错

wb+”读写

为了读写数据,建立新的二进制文件

建立新文件

ab+”读写

为了读写数据,打开二进制文件

报错

fclose 函数的参数为文件指针。该函数用来关闭文件,即撤销文件指针。若果成功执行了关闭操作则返回0,否则返回 EOF(01)。

3、顺序读写文件

顺序读写文件就是从文件的开头开始按顺序进行遍历读写操作,也即按照文件数据的物理存放顺序进行读写。有关库函数的使用列表如下:

函数名

调用方式

功能

返回值

fgetc

fgetc(fp)

fp 指向的文件中读入一个字符

返回所读的字符,若失败则返回 EOF

fputc

fputc(ch, fp)

fp 指向的文件中写入一个字符

返回所写的字符,若失败则返回 EOF

fgets

fgets(str, n, fp)

fp 指向的文件中读入一个长度为 (n-1) 字符串存放到字符数组 str

读成功返回地址 str ,否则返回 NULL

fputs

fputs(str, fp)

str 所指向的字符串写到文件指针 fp 所指的文件中

写成功返回 0,否则返回非 0

函数名中 c 表示字符 character,s 表示字符串 string

系统使用文件读写位置标记来表示当前的访问位置,开始时指向第一个字节,每进行一次读写操作,就自动按顺序移向下一个要读写的位置。程序中可以使用 feof(fp) 函数来判断 文件读写位置标记 是否移到文件末尾,即磁盘文件是否结束,如果是则返回1,否则返回0,一般用于读文件。

注意 putchar() 与 getchar() 函数为从终端对内存变量进行读写操作的函数。

fgets 与 fputs 的函数原型为:

char* fgets(char* str, int n, FILE *fp)
char* fputs(char* str, FILE *fp)

使用格式化方式读写文件

函数调用如下:

fprintf(文件指针, 格式字符串, 输出列表);
fscanf(文件指针, 格式字符串, 输出列表);

这两个函数使用方式与 printf 和 scanf 差不多,只是后者的输入输出都是在终端中进行的,前者是在文件中进行的。如下例子

// 向文件中写入两个数据,最种在文本文件中呈现为: 1, 3.14
fprintf(fp, "%d,%5.2f", i, f);
// 如果磁盘文件上有字符: 1, 3.14 以下操作从此盘中读取这两个数字存入相应的变量中
fscanf(fp, "%d,%f", i, f);

 由前述文件分类可知,格式化读写文件涉及数据的 二进制 与 ASCII 格式的转换,因此在频繁进行磁盘文件操作的场合效率较低,在这种场景下我们可以进行二进制的读写。

使用二进制方式读写文件

fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);

使用 fread 函数在进行读操作时直接从文件中读取一个原始的二进制数据块,在使用 fwrite 函数进行写数据操作时也是直接向文件中写入原始未经转换的二进制数据。另外需要注意的是,使用这两个函数的前提是在打开文件时要以二进制方式打开

四个参数中:

  • buffer 是一个地址,对 fread 函数来说就是从文件中读入数据的存储区的地址,对 fwrite 来说就是把此地址开始的数据写入文件。
  • size 是要读/写的数据项的字节数(数据项可以是单个数据类型,比如 char、int、float 等,也可以是一个结构体等数据块)
  • count 是要读/写多少个数据项
  • fp 是要读/写的 FILE 类型文件指针

fread 函数的返回值

  • 返回成功读取的对象个数,若出现错误或到达文件末尾,则可能小于 count。
  • 若 size 或 count 为零,则 fread 返回零且不进行其他动作。
  • fread 不区分文件尾和错误,因此调用者必须用 feof() 和 ferror() 才能判断发生了什么。

4、随机读写文件

一般在使用文件数据时,很少从文件开头进行数据遍历读写的,这样效率太低。我们大多数时候需要从文件中间某个地方的数据进行读取,在跳到另外一个地方进行操作,显然前述的顺序读写操作不适合这种场景,这时就需要对文件的随机读写操作,随机在这里也就是任意位置的意思。

对文件进行随机读写的原理就是对前面提到的 文件读写位置标记 进行自定义的定位,来达到自定义文件读写位置的效果。

  • 使用 rewind(fp) 函数可以将文件位置标记指向文件开头。
  • 使用 fseek() 函数改变文件的位置标记,其调用形式为:
fseek(文件类型指针, 位移量, 起始点)

第三个参数 起始点 具有三个固定的枚举参数值:

  • SEEK_SET :代表文件开始位置,也可用数字 0 代替
  • SEEK_CUR:代表文件开始位置,也可用数字 1 代替
  • SEEK_END:代表文件末尾位置,也可用数字 2 代替

位移量 就是以 起始点 为基点移动的字节数,为正就是向前移动,为负就是向后移动,数据类型为 long 型,因此需要在数字末尾加上 L ,如:

fseek(fp, 10L, 0);  // 将文件位置标记向前移动到离文件开头 100 个字节处
fseek(fp, -10L, 1); // 将文件位置标记向后移动到离文件当前位置 10 个字节处

可能在看代码时还会遇到名为 fseeko 或者 fseeko64 的函数,这两个函数的作用与 fseek 函数一样,唯一的不同就是 偏移量 的数据类型,前两个分别为 off_t 和 off64_t 。(off_t 及 off64_t 均为 typedef 数据,原型分别为 long int 和 long long)

  • 使用 ftell() 函数返回 文件读写位置标记 的当前位置,返回值为 long 型,该值是相对于文件开头位置的偏移量来计算的。
long i = ftell(fp);

如果返回值为 -1L ,则说明函数调用失败。

5、其他与文件相关的操作

最近在看 GNU Radio 源码时发现了其他一些文件操作有关的函数,记录如下:

  •  stat() 函数

stat 函数定义在 sys/stat.h 头文件中,用来获取文件当前的状态。其函数定义为:

int stat(const char * file_name, struct stat *buf);

参数 file_name 为文件的路径名,函数将该路径下的文件的状态保存在 stat 结构体指针 buf 中,该结构体包含文件设备编号(st_dev)、文件类型和存取权限(st_mode)、文件大小(st_size)方面的信息。

  •  fstat() 函数

fstat 函数同样定义在 sys/stat.h 头文件中,通过文件描述符来获取文件的状态。其函数定义为:

int fstat(int filedes, struct stat *buf);

该函数一般用于已打开的文件。当文件打开之后系统为其分配一个专门的文件描述符 filedes(file descriptor),可以使用 fileno(FILE* fp) 来获取。文件描述符在形式上是一个非负整数,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。buf 参数同样是用来保存文件状态信息的结构体。

以上两个函数若执行成功则返回 0 ,否则返回 -1 。

stat 结构体具体定义如下(头文件中对 stat 结构体的定义包含一些预处理代码,以下为精简版):

struct stat {
    dev_t st_dev; //device 文件的设备编号
    ino_t st_ino; //File serial number 文件的32位序列号
    mode_t st_mode; //protection 文件的类型和存取的权限
    nlink_t st_nlink; //number of hard links 连到该文件的硬连接数目, 刚建立的文件值为1.
    uid_t st_uid; //user ID of owner 文件所有者的用户识别码
    gid_t st_gid; //group ID of owner 文件所有者的组识别码
    dev_t st_rdev; //device type 若此文件为装置设备文件, 则为其设备编号
    off_t st_size; //total size, in bytes 文件大小, 以字节计算
    unsigned long st_blksize; //blocksize for filesystem I/O 文件系统的I/O 缓冲区大小.
    u nsigned long st_blocks; //number of blocks allocated 占用文件区块的个数, 每一区块大小为512 个字节.
    time_t st_atime; //time of lastaccess 文件最近一次被存取或被执行的时间, 一般只有在用mknod、 utime、read、write 与tructate 时改变.
    time_t st_mtime; //time of last modification 文件最后一次被修改的时间, 一般只有在用mknod、 utime 和write 时才会改变
    time_t st_ctime; //time of last change i-node 最近一次被更改的时间, 此参数会在文件所有者、组、 权限被更改时更新
};

执行上述函数,获取相关信息(部分)的大致流程如下:

#include "sys/stat.h"
 ......
FILE *fp;
fp = fopen("path/to/yourfile", "yourOpenModeString")  // 打开文件
......
struct stat st;  // 定义 stat 类型的结构体
stat("path/to/yourfile", &st)  // 获取文件结构体
// fstat(fileno(fp), &st)  // 这样也可获取文件结构体
 ......
// 判断相关状态的一些宏定义函数
S_ISLNK (st.st_mode)  // 判断是否为符号连接 
S_ISREG (st.st_mode)  // 是否为一般文件 
S_ISDIR (st.st_mode)  // 是否为目录 
S_ISCHR (st.st_mode)  // 是否为字符装置文件 
S_ISSOCK (st.st_mode) // 是否为socket 若一目录具有sticky 位 (S_ISVTX), 则表示在此目录下的文件只能 被该文件所有者、此目录所有者或root 来删除或改名. 

其他的可参考:

C语言stat()函数:获取文件状态_C语言中文网

linux stat函数讲解 - Leo Chin - 博客园

有关文件描述符与文件指针的区别可看:

open和fopen的区别_Herok-CSDN博客

——以上内容总结整理自谭浩强的《C语言程序设计(第四版)》——

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C/C++ 文件操作基础 的相关文章

随机推荐

  • MATLAB的appdesigner背景图片设置

    MATLAB的appdesigner背景图片设置 工作环境 xff1a windows10 MATLAB2017a 转变MATLAB2019b 前面因为课程需要做了一个简单的MATLABapp xff0c 在进行app背景图片设置的时候 x
  • ros-话题节点消息控制rviz中机械臂Publish Joint_State with Python to RVIZ-ros回炉再强学习(6)

    ros 话题节点消息Publish Joint State with Python to RVIZ ros回炉再强学习 xff08 6 xff09 笔者工作环境 xff1a ubuntu16 04 ros kinect 代码下载地址 xff
  • opencv边缘检测运用sobel算子源代码方法

    opencv边缘检测运用sobel算子源代码方法 span class token function import span cv2 span class token function import span numpy as np spa
  • v-rep仿真之键盘控制机械臂末端移动

    v rep仿真之键盘控制机械臂末端移动 键盘控制机械臂末端移动原理为 xff0c 设置机械臂逆运动学target xff0c 机械臂末端跟随target运动 xff0c 然后通过改变target的值 xff0c 从而达到控制机械臂末端移动的
  • urx驱动ur3和onrobot rg2

    urx驱动ur3和onrobot rg2 注意 xff1a 非常重要的一点 xff0c urx是可以在Python2和Python3都支持的 xff0c 随着时间改变 xff0c 如果有的读者发现Python2中不能使用 xff0c 报错m
  • ros-melodic安装解决sudo rosdep init问题

    ros melodic安装解决sudo rosdep init问题 解决办法1 去网站查看raw githubusercontent com的真实IP span class token function sudo span span cla
  • 上电浪涌电流

    上电浪涌电流 电机启动或者停转都会形成浪涌电流 xff0c 例如启动的浪涌最大 xff0c 毕竟电机启动静态电阻非常小 xff0c 上电等同短路 xff0c 其电机为感性负载 xff0c 由较大的无功电流 xff0c 对电网造成波动非常大
  • 电机功率计算公式

    电机功率计算公式 电动机输入功率 单相电机为P 61 UI xff0c 三相电机P 61 UIcos0 8 输出功率 xff08 驱动功率 xff09 P 61 FV F为力 牛顿 V xff1a 速度 m S xff09 换算到电机则有
  • C++ 中 map 字典与 set 集合的使用

    在 C 43 43 中 xff0c map 是关联容器 的一种 xff0c 关联容器将值 与键 关联到一起 xff0c 并使用键来查找值 这与 python 中的字典 类型类似 xff0c 也是用来存储键 值对 xff08 key valu
  • win11 安装 WSL2 在非 C 盘及配置(图形界面+代理)

    WSL 安装及配置 直接安装 WSL2 在非 C 盘启用 WSL 功能前提条件设置默认安装 WSL2安装在非 C 盘 图形界面先决条件更新 WSL 以支持 GUI 配置 WSL2 使用 Windows 网络代理 直接安装 WSL2 在非 C
  • CVTE嵌入式实习生与秋招

    目录 前言一 实习笔试二 实习面试三 实习工作内容四 公司看法 前言 今年暑假去CVTE实习了一个多月最后经过转正答辩 xff0c 获得了offer xff0c 现就我的实习经历和对公司的一些认知分享一下 xff08 仅代表个人观点 xff
  • 视频编解码行业及发展方向简述

    目录 一 视频行业1 视频是一个方兴未艾的大产业2 视频行业潜在商机大 人才缺口大3 了解华为海思的HI3518E方案 二 海思方案项目用到的硬件平台介绍1 本专栏文章使用的开发板配置2 处理器为什么选HI3518E 三 本专栏文章规划和核
  • 全面认识海思SDK及嵌入式层开发(1)

    目录 一 全面认识和检测配套开发套装1 套装配件介绍2 检测开发板3 注意 二 视频设备开发的技术流1 视频从产生到被消费的整个流程2 视频行业的商业角度分段3 几个疑问点 一 全面认识和检测配套开发套装 购买方式 xff1a 淘宝搜索 g
  • 嵌入式linux开发环境搭建(VMware16.0.0+Ubuntu16.04.3_X64)

    目录 一 安装VMware1 VMware介绍2 安装VMware16 0 0 二 安装ubuntu16 04 3 LTS1 Ubuntu介绍2 下载安装包iso3 安装 四 新安装Ubuntu的基本设置1 开机和关机等2 虚拟机基本设置3
  • 全面认识海思SDK及嵌入式层开发(2)

    目录 一 HI3518E方案系统整体架构介绍1 硬件上2 软件上 二 海思SDK的整体介绍三 海思SDK包的学习和实验1 2篇相关文档2 SDK包复制到linux原生目录中并解压3 SDK包操作的脚本程序研究4 SDK中源码包部分的配置编译
  • 计算机视觉之相机模型

    目录 一 相机模型1 相机与图像2 坐标系3 世界坐标系到摄像机坐标系4 摄像机坐标系到图像物理坐标系5 图像物理坐标系到图像像素坐标系6 摄像机坐标系到图像像素坐标系7 世界坐标系到图像像素坐标系 二 镜头畸变1 相机成像原理2 镜头畸变
  • vscode安装插件失败,完美解决

    vscode安装插件一直失败 xff0c 解决方案如下 访问vscode插件官网https marketplace visualstudio com vscode xff0c 搜索你要的插件点击插件详情 Version History 下载
  • ROS的topic通信机制

    1 通信步骤如图 xff1a 2 步骤介绍 第 xff08 0 xff09 步 xff1a talker gt master 发布者talker向mater注册 xff1a 包括节点的信息 需要发布的话题名等 xff0c 然后节点管理器RO
  • 关于快速幂和矩阵快速幂

    快速幂 xff1a 可参考该链接百科快速幂也可以参考这个博客快速幂博客 给出快速幂的题目和代码 xff1a 快速幂 取余计算 include lt iostream gt include lt string h gt using names
  • C/C++ 文件操作基础

    目录 1 文件分类 2 文件的打开与关闭 3 顺序读写文件 4 随机读写文件 5 其他与文件相关的操作 最近看 GNU Radio 源码看到了文件操作的部分 xff0c 因此记录下学习 C 43 43 C 操作文件的过程 本文的文件操作是