编辑这个页面须要登录或更高权限!

C 语言文件读写

在本教程中,您将学习如何在C语言中处理文件。您将通过示例学习在C语言中使用fprintf()、fscanf()、fread()、fwrite()、fseek()等处理标准I/O。

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

为什么需要文件?

  • 当程序终止时,所有数据都会丢失。即使程序终止,存储在文件中也会保留您的数据。

  • 如果必须输入大量数据,则将花费大量时间来全部输入。
    但是,如果您有一个包含所有数据的文件,则可以使用C中的一些命令方法轻松地访问文件的内容。

  • 您可以轻松地将数据从一台计算机移动到另一台计算机,而无需进行任何更改。

文件类型

处理文件时,您应该了解两种类型的文件:

  1. 文本文件

  2. 二进制文件

1.文本文件

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

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

它们以最少的维护工作,易于阅读,提供最少的安全性并占用更大的存储空间。

2.二进制文件

二进制文件主要是计算机中的.bin文件。

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

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

文件操作

在C中,您可以对文件执行四个主要操作:

  1. 创建一个新文件

  2. 打开现有文件

  3. 关闭文件

  4. 读取信息并将信息写入文件

处理文件

处理文件时,需要声明文件类型的指针。文件和程序之间的通信需要此声明。

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()的文件版本。 唯一的区别是fprint()和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。

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

示例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,并将其在主函数中定义为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", num.n1, num.n2, num.n3);
   }
   fclose(fptr); 
  
   return 0;
}

在此程序中,您读取相同的文件program.bin,并逐个循环浏览记录。

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

您将获得与示例3中插入的记录相同的记录。

使用fseek()获取数据

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

这将浪费大量的内存和操作时间。使用fseek()可以轻松获得所需数据。

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

fseek()的语法

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

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

fseek()中的不同位置
位置含义
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中读取记录并进行打印。