跳到主要内容

C 语言文件处理

提示
  1. 文件的重要性:文件用于永久存储数据,避免程序终止时数据丢失,并便于数据在计算机间传输。
  2. 文件类型:C语言中有两种文件类型:文本文件(.txt)和二进制文件(.bin),它们在存储和安全性方面有所不同。
  3. 文件操作:在C中,文件操作包括创建、打开、关闭以及读写文件。使用fopen()来打开或创建文件,fclose()来关闭文件,fprintf()fscanf()来读写文本文件,fwrite()fread()来处理二进制文件。

文件是计算机存储设备中用于存储数据的容器。

为什么需要文件?

  • 当程序终止时,所有数据都会丢失。存储在文件中可以在程序终止后保留您的数据。
  • 如果您需要输入大量数据,将需要花费很多时间进行输入。 然而,如果您有一个包含所有数据的文件,您可以使用C语言中的一些命令轻松访问文件内容。
  • 您可以轻松地将数据从一台计算机移动到另一台计算机,而无需进行任何更改。

文件类型

处理文件时,您需要了解两种类型的文件:

  1. 文本文件
  2. 二进制文件

1. 文本文件

文本文件是正常的 .txt 文件。您可以使用任何简单的文本编辑器(如记事本)轻松创建文本文件。

打开这些文件时,您会看到文件中所有内容都以纯文本形式显示。您可以轻松地编辑或删除内容。

它们维护起来最省力,易于阅读,提供最低的安全性并占用更大的存储空间。

2. 二进制文件

二进制文件在您的计算机上大多是 .bin 文件。

它们不是以纯文本形式存储数据,而是以二进制形式(0和1)存储。

它们可以容纳更多数据,不易于阅读,并且比文本文件提供更好的安全性。

文件操作

在C语言中,您可以对文件(无论是文本还是二进制)执行四种主要操作:

  1. 创建新文件
  2. 打开现有文件
  3. 关闭文件
  4. 读取和写入文件信息

文件操作

处理文件时,您需要声明一个类型为file的指针。这种声明是文件与程序之间通信所必需的。

FILE *fptr;

打开文件 - 用于创建和编辑

使用 stdio.h 头文件中定义的 fopen() 函数来打开文件。

打开文件的标准I/O语法是:

ptr = fopen("fileopen","mode");

例如,

fopen("E:\\cprogram\\newprogram.txt","w");

fopen("E:\\cprogram\\oldprogram.bin","rb");
  • 假设文件 newprogram.txt 不存在于 E:\\cprogram 的位置。第一个函数创建一个名为 newprogram.txt 的新文件,并根据模式 'w' 打开它以供写入。 写入模式允许您创建和编辑(覆盖)文件内容。
  • 现在假设第二个二进制文件 oldprogram.bin 存在于 E:\\cprogram 的位置。第二个函数以二进制模式 'rb' 打开现有文件以供读取。 读取模式仅允许您读取文件,您不能写入文件。

标准I/O中的打开模式

模式模式的含义文件不存在时
r用于读取。如果文件不存在,fopen() 返回 NULL。
rb以二进制模式用于读取。如果文件不存在,fopen() 返回 NULL。
w用于写入。如果文件存在,其内容将被覆盖。 如果文件不存在,将被创建。
wb以二进制模式用于写入。如果文件存在,其内容将被覆盖。 如果文件不存在,将被创建。
a用于追加。 数据将添加到文件的末尾。如果文件不存在,将被创建。
ab以二进制模式用于追加。 数据将添加到文件的末尾。如果文件不存在,将被创建。
r+用于读写。如果文件不存在,fopen() 返回 NULL。
rb+以二进制模式用于读写。如果文件不存在,fopen() 返回 NULL。
w+用于读写。如果文件存在,其内容将被覆盖。 如果文件不存在,将被创建。
wb+以二进制模式用于读写。如果文件存在,其内容将被覆盖。 如果文件不存在,将被创建。
a+用于读取和追加。如果文件不存在,将被创建。
ab+以二进制模式用于读取和追加。如果文件不存在,将被创建。

关闭文件

读写后应关闭文件(无论是文本文件还是二进制文件)。

使用 fclose() 函数来关闭文件。

fclose(fptr);

这里,fptr 是与要关闭的文件相关联的文件指针。

读写文本文件

对于文本文件的读写,我们使用 fprintf()fscanf() 函数。

它们只是 printf()scanf() 的文件版本。唯一的区别是 fprintf()fscanf() 需要一个指向结构 FILE 的指针。

示例 1:写入文本文件

#include <stdio.h>
#include <stdlib.h>

int main()
{
int num;
FILE *fptr;

// 如果您使用的是MacOS或Linux,请使用适当的位置
fptr = fopen("C:\\program.txt","w");

if(fptr == NULL)
{
printf("Error!");
exit(1);
}

printf("Enter num: ");
scanf("%d",&num);

fprintf(fptr,"%d",num);
fclose(fptr);

return 0;
}

这个程序从用户那里获取一个数字并将其存储在文件 program.txt 中。

编译并运行此程序后,您可以在计算机的C驱动器中看到一个名为 program.txt 的文本文件。打开该文件时,您可以看到输入的整数。

示例 2:从文本文件读取

#include <stdio.h>
#include <stdlib.h>

int main()
{
int num;
FILE *fptr;

if ((fptr = fopen("C:\\program.txt","r")) == NULL){
printf("Error! opening file");

// 如果文件指针返回 NULL,则程序退出。
exit(1);
}

fscanf(fptr,"%d", &num);

printf("Value of n=%d", num);
fclose(fptr);

return 0;
}

此程序读取 program.txt 文件中的整数并将其打印到屏幕上。

如果您成功创建了 示例 1 中的文件,则运行此程序会得到您输入的整数。

fgetchar()fputc() 等其他函数也可以以类似方式使用。

读写二进制文件

函数 fread()fwrite() 用于分别从磁盘读取和向磁盘写入二进制文件。

写入二进制文件

要写入二进制文件,您需要使用 fwrite() 函数。该函数接受四个参数:

  1. 要写入磁盘的数据的地址
  2. 要写入磁盘的数据的大小
  3. 这种类型的数据的数量
  4. 指向您要写入的文件的指针。
fwrite(addressData, sizeData, numbersData, pointerToFile);

示例3:使用 fwrite() 写入二进制文件

#include <stdio.h>
#include <stdlib.h>

struct threeNum
{
int n1, n2, n3;
};

int main()
{
int n;
struct threeNum num;
FILE *fptr;

if ((fptr = fopen("C:\\program.bin","wb")) == NULL){
printf("Error! opening file");

// 如果文件指针返回NULL,则程序退出。
exit(1);
}

for(n = 1; n < 5; ++n)
{
num.n1 = n;
num.n2 = 5*n;
num.n3 = 5*n + 1;
fwrite(&num, sizeof(struct threeNum), 1, fptr);
}
fclose(fptr);

return 0;
}

在这个程序中,我们在C盘创建了一个新文件program.bin

我们声明了一个包含三个数字 - n1、n2 和 n3 的结构体threeNum,并在main函数中将其定义为num。

现在,在for循环内,我们使用fwrite()将值存入文件。

第一个参数取num的地址,第二个参数取结构体threeNum的大小。

因为我们只插入一个num实例,所以第三个参数是1。最后一个参数*fptr指向我们存储数据的文件。

最后,我们关闭文件。

从二进制文件读取

函数fread()也像fwrite()函数一样接受4个参数。

fread(addressData, sizeData, numbersData, pointerToFile);

示例4:使用 fread() 从二进制文件读取

#include <stdio.h>
#include <stdlib.h>

struct threeNum
{
int n1, n2, n3;
};

int main()
{
int n;
struct threeNum num;
FILE *fptr;

if ((fptr = fopen("C:\\program.bin","rb")) == NULL){
printf("Error! opening file");

// 如果文件指针返回NULL,则程序退出。
exit(1);
}

for(n = 1; n < 5; ++n)
{
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
}
fclose(fptr);

return 0;
}

在这个程序中,你读取同一个文件program.bin并一条一条地遍历记录。

简单来说,你从文件*fptr指向的文件中读取一个threeNum大小的threeNum记录到结构体num中。

你将获取到你在示例3中插入的相同记录。

使用 fseek() 获取数据

如果文件中有许多记录并且需要访问特定位置的记录,你需要遍历其前面的所有记录才能获取该记录。

这将浪费大量的内存和操作时间。使用fseek()可以更容易地获取所需数据。

顾名思义,fseek()将光标定位到文件中给定记录的位置。

fseek() 的语法

fseek(FILE * stream, long int offset, int whence);

第一个参数stream是指向文件的指针。第二个参数是要找到的记录的位置,第三个参数指定偏移量的起始位置。

fseek() 中的不同whence

Whence意义
SEEK_SET从文件开头开始偏移量。
SEEK_END从文件末尾开始偏移量。
SEEK_CUR从文件中光标的当前位置开始偏移量。

示例5:fseek()

#include <stdio.h>
#include <stdlib.h>

struct threeNum
{
int n1, n2, n3;
};

int main()
{
int n;
struct threeNum num;
FILE *fptr;

if ((fptr = fopen("C:\\program.bin","rb")) == NULL){
printf("Error! opening file");

// 如果文件指针返回NULL,则程序退出。
exit(1);
}

// 将光标移动到文件末尾
fseek(fptr, -sizeof(struct threeNum), SEEK_END);

for(n

= 1; n < 5; ++n)
{
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
fseek(fptr, -2*sizeof(struct threeNum), SEEK_CUR);
}
fclose(fptr);

return 0;
}

这个程序将从文件program.bin中反向(从最后到第一个)读取记录并打印出来。