【落羽的落羽 C语言篇】文件操作

发布于:2025-02-10 ⋅ 阅读:(46) ⋅ 点赞:(0)

在这里插入图片描述

文章目录

  • 一、文件的概念和分类
    • 1. 概念和分类
    • 2. 文件名
    • 3. 数据文件
  • 三、文件操作
    • 1. 文件的打开和关闭
      • 1.1 流
      • 1.2 文件指针
      • 1.3 文件的打开和关闭
    • 2. 文件的顺序读写
    • 3. 文件的随机读写
    • 4. 文件读取的判定
    • 5. 文件缓冲区

一、文件的概念和分类

1. 概念和分类

文件是用来保存数据的。如果没有文件,我们写的程序会直接存储在电脑内存中,如果程序退出,内存被释放回收,数据就丢失了。所以如果要将数据进行持久化的保存,我们就可以使用文件来保存数据。
在生活中,我们一般直接将电脑磁盘中的文件称之为文件。而在程序设计中,我们所说的文件一般分为两种:程序文件、数据文件。

  • 程序文件包括:源程序文件(后缀为.c)、目标文件(Windows环境下后缀为.obj)、可执行程序(后缀为.exe)以后会再次介绍的。
  • 数据文件的内容,是程序运行时读写的数据,包括程序运行时需要从中读取数据的文件,或者输出内容的文件。

在之前C语言的学习过程中,我们对数据的输出输入都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。但有时候我们也需要把数据输出到磁盘中,也需要从磁盘中读取数据到内存中来使用,这时就是对磁盘里的文件进行文件操作了。

2. 文件名

我们还要知道的是:一个文件通常要有一个唯一的文件标识以便于使用者识别和引用,这就是文件名,通常包含“文件路径、文件名主干、文件后缀”三部分。
举个例子,在我的电脑磁盘中有:
在这里插入图片描述右键点击复制文件地址,能得到这个文件的文件名是:
D:\ACG电吉\春日影\Final春日影 吉他.pdf
其中,这个文件本身的名字“Final春日影 吉他”,是文件名主干。
前面的“D:\ACG电吉\春日影\”,是文件路径。
最后的“.pdf”,是文件后缀。

很简单对吧。

3. 数据文件

数据文件还可以再分为文本文件和二进制文件。

  • 文本文件:数据以ASCII值的形式存储的文件
  • 二进制文件:数据以二进制的形式存储的文件

字符型数据一律用ASCII值形式存储,数值型数据既可以用ASCII值形式存储也可以用二进制形式存储。
它们的区别是什么呢?举个栗子,整数12345

  • 如果以ASCII形值式输出到磁盘中,则占用五个字节(一个字符占据一个字节),内容是00110001 00110010 00110011 00110100 00110101(即ASCII值49、50、51、52、53,对应字符“1”、“2”、“3”、“4”、“5”)
  • 如果以二进制形式输出到磁盘中,则占用四个字节(int大小),内容是00000000 00000000 00110000 00111001(就是12345的二进制表示)

在这里插入图片描述

三、文件操作

1. 文件的打开和关闭

1.1 流

流是计算机领域一个抽象但重要的概念。
简单来说,程序需要跟各种外部设备交互,外部设备包括键盘、显示器、磁盘、U盘、网络等等,程序的数据需要输出到各种外部设备上,也需要从各种外部设备获取数据,不同的外部设备的输入输出操作各不相同。为了方便程序员对各种设备的操作,人们抽象出了“流”的概念。“流”就像一条流淌着数据的河,程序和外部设备将数据都投入这条“河”中,或者各取所需的数据。C语言内部处理好外部设备和流的数据传递,而程序设计者只要再考虑程序如何与流交互就好了。
一般情况下,我们想要往流里写数据,或者从流里读取数据,都是先打开流,然后再操作。

那么,为什么我们以前写C语言程序,从键盘上读取数据,向屏幕上输出数据,并没有打开流的操作呢?这是因为C语言程序在启动时,默认会打开三个流:

  • stdin(标准输入流):它在大多数环境下能从键盘输入数据,scanf函数就是从这个流中读取数据的
  • stdout(标准输出流):它在大多数环境下能输出数据至显示器界面,printf函数就是将信息输出到这个流中的
  • stderr(标准错误流):它在大多数环境下能输出数据至显示器界面

这三个流的类型是FILE*,被称为文件指针。在C语言中,就是通过文件指针来维护流的各种操作的。

1.2 文件指针

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息,比如文件的名字、状态、位置等等。这些信息被保存在一个结构体变量中,该结构体变量是由系统声明的,被typedef重命名为FILE。不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
使用者打开一个文件时,系统会根据文件的情况自动创建一个FILE类型的变量,自动填充好内部信息,使用者不必关心具体细节。
为了维护这个FILE结构的变量,一般使用FILE*类型的指针,这就是文件指针。比如,定义一个FILE* pf;可以使pf指向某个文件的文件信息区,通过该文件信息区的信息来操作该文件,换句话说,通过文还指针能够间接找到与它相关联的文件。

1.3 文件的打开和关闭

读写文件之前应该先打开文件,使用后应该关闭文件。ANSI C规定使用fopen函数打开文件,fclose函数关闭文件。它们(和以下函数)包括在头文件stdio.h中
在这里插入图片描述在这里插入图片描述fclose的使用方式很简单,参数就是需要关闭的文件的文件指针。

fopen的使用较为复杂:

FILE* fopen(const char* filename, const char* mode);

它的返回值是打开的文件的文件指针。
它的第一个参数是文件名,第二个参数是文件的打开模式,有以下模式及其作用:

文件打开模式 含义 如果指定文件不存在
r(只读) 为了输入数据,打开一个文本文件 返回空指针
w(只写) 为了输出数据,打开一个文本文件 创建一个新的文件(如果文件存在,会清空原内容)
a(追加) 向文本文件尾添加数据 创建一个新的文件
rb(只读) 为了输入数据,打开一个二进制文件 返回空指针
wb(只写) 为了输出数据,打开一个二进制文件 创建一个新的文件
ab(追加) 向二进制文件尾添加数据 创建一个新的文件
r+(读写) 为了读写数据,打开一个文本文件 返回空指针
w+(读写) 为了读写数据,打开一个文本文件 创建一个新的文件
a+(读写) 在文本文件尾读写数据 创建一个新的文件
rb+(读写) 为了读写数据,打开一个二进制文件 返回空指针
wb+(读写) 为了读写数据,创建一个二进制文件 创建一个新的文件
ab+(读写) 在二进制文件尾读写数据 创建一个新的文件

举例,一开始我的项目文件夹里没有data.txt这个文件
如果有FILE* pf = fopen("data.txt","r");在这里插入图片描述

如果是FILE* pf = fopen("data.txt","w");就会在这个代码项目的文件夹中创建这样一个文件:
在这里插入图片描述
当然,我们还可能需要从电脑的其他磁盘上的其他文件中读写数据,就需要明白绝对路径和相对路径的表示方法:

  • 绝对路径就是一个文件的完整文件名,比如之前提到过的 D:\ACG电吉\春日影\Final春日影 吉他.pdf
  • 相对路径要用...表示,.表示当前路径,..表示上一级路径。每一级中间本来需要用\分割,但在C语言中需要被转义,即要用转义字符\\表示\

举个栗子,我的电脑中一开始没有data.txt这个文件,我的C语言程序源文件位置如下:
在这里插入图片描述

如果在程序中以w模式打开一个D盘文件data.txt,就会自动创建

  • 用绝对路径表示:fopen("D:\\data.txt","w");
  • 用相对路径表示:fopen(".\\..\\..\\..\\..\\data.txt","w");
    在这里插入图片描述

都是成功的

2. 文件的顺序读写

文件的顺序读写涉及到一系列函数:

函数 功能 适用于
fgetc 字符输入 所有输入流
fputc 字符输出 所有输出流
fgets 按文本行输入 所有输入流
fputs 按文本行输出 所有输出流
fscanf 格式化输入 所有输入流
fprintf 格式化输出 所有输出流
fread 二进制输入 文件输入流
fwrite 二进制输出 文件输出流

这些函数的使用大同小异,我们就举两个例子,其余大家自己查阅了解即可

在这里插入图片描述fputs函数的第一个参数是要写入的字符串,第二个参数是要写进的文件

在这里插入图片描述fgetc函数的参数是要从中读取字符的文件

#include<stdio.h>
int main()
{
    FILE* pf = NULL;

    pf = fopen("data.txt", "w");
    fputs("TECH OTAKUS SAVE THE WORLD", pf);
    fclose(pf);

    pf = fopen("data.txt", "r");
    int n = 0;
    while(n++ < 5)
        printf("%c\n", fgetc(pf));
    fclose(pf);

    return 0;
}

结果很显然,程序创建了一个文本文件写入了一些内容,然后打印出前四个字符。
在这里插入图片描述在这里插入图片描述

3. 文件的随机读写

上面的函数只能对文件内容按顺序读写,有时我们也需要对内容按照特定顺序读写,这就是文件的随机读写。要用到以下函数:

  • fseek
    在这里插入图片描述这个函数能改变文件光标的位置,“文件光标”就是读写数据的位置,可以理解成我们在电脑手机上打字的这个光标。
    在这里插入图片描述

    第一个参数是文件指针,第二个参数是你想要的偏移量,第三个参数是你想从哪个位置计算偏移量。第三个参数是有三个取值的:在这里插入图片描述SEEK_SET是文件的开头,SEEK_CUR是当前光标的位置,SEEK_END是文件的末尾。
    光标位置是怎么决定的呢?比如文件指针pf刚刚进行了写数据,其指向的文件里刚写下了abcdef,此时光标在末尾,即f后的位置。如果有fseek(pf, 2, SEEK_SET);光标在文本开头后偏移2个位置,即b和c中间。假如我们再写一次数据,就会从这里开始写,新写入的数据会覆盖掉刚才的几个字符:在这里插入图片描述偏移量负值代表左偏移,正值代表右偏移。所以,对于abcdeffseek(pf, 2, SEEK_SET)fseek(pf, -4, SEEK_END)的效果其实是一样的

    再举例一个用法,fgetc读取字符是从文件开头向后一个一个读的。因为光标起始位置是开头,每次读光标之后的一个字符,然后光标向右偏移1。但我们不想按这样的顺序读数据时,就可以用fseek函数实时调整光标的位置了。

  • ftell在这里插入图片描述很简单,它的参数是文件指针,这个函数能返回这个文件中当前光标相对于开头的偏移量

  • rewind在这里插入图片描述这个函数能让参数文件的光标返回起始位置

4. 文件读取的判定

不同的函数读取到文件末尾时的标识不一样,比如fgets读取结束会返回NULL,fgetc读取结束会返回EOF,等等。对于二进制文件,fread的返回值小于实际要读取的个数,说明读取结束

5. 文件缓冲区

最后一个简单的知识点:ASNI C标准采用“缓冲文件系统”处理数据文件,它指系统自动在内存中为程序每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据,会先送到文件缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机输入数据,则从磁盘文件中读取数据输入到内存缓冲区,然后再从缓冲区逐个地将数据送到程序数据区。缓冲区的大小由C编译系统决定。因为由缓冲区的存在,所以C语言在进行文件操作时,需要刷新缓冲区或者结束时关闭文件。如果不做,可能有读写文件的问题。

在这里插入图片描述
本篇完,感谢阅读~


网站公告

今日签到

点亮在社区的每一天
去签到