# C 文件处理

> 原文： [https://www.programiz.com/c-programming/c-file-input-output](https://www.programiz.com/c-programming/c-file-input-output)

#### 在本教程中，您将学习 C 语言中的文件处理。您将学习在示例的帮助下使用`fprintf()`，`fscanf()`，`fread()`，`fwrite()`，`fseek()`等在 C 中处理标准 I/O。 

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

* * *

## 为什么需要文件？

*   当程序终止时，所有数据都会丢失。 即使程序终止，存储在文件中也会保留您的数据。
*   如果必须输入大量数据，则将花费大量时间来全部输入。
    但是，如果您有一个包含所有数据的文件，则可以使用 C 中的一些命令轻松访问该文件的内容。
*   您可以轻松地将数据从一台计算机移动到另一台计算机，而无需进行任何更改。

* * *

## 文件类型

处理文件时，您应该了解两种类型的文件：

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

### 1.文本文件

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

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

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

### 2.二进制文件

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

它们不是以纯文本格式存储数据，而是以二进制格式（0 和 1）存储数据。

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

* * *

## 文件操作

在 C 中，您可以对文件执行四个主要操作，即文本或二进制：

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

* * *

## 处理文件

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

```c
FILE *fptr;
```

* * *

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

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

在标准 I/O 中打开文件的语法为：

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

```

例如，

```c
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()`函数关闭文件。

```c
fclose(fptr);
```

在此，`fptr`是与要关闭的文件相关联的文件指针。

* * *

## 读取和写入文本文件

为了读取和写入文本文件，我们使用函数`fprintf()`和`fscanf().`

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

* * *

### 示例 1：写入文本文件

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

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

   // use appropriate location if you are using MacOS or 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：读取文本文件

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

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

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

       // Program exits if the file pointer returns 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.  指向要写入的文件的指针。

```c
fwrite(addressData, sizeData, numbersData, pointerToFile);
```

* * *

### 示例 3：使用`fwrite()`写入二进制文件

```c
#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");

       // Program exits if the file pointer returns 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()`也采用 4 个自变量，类似于上面的`fwrite()`函数。

```c
fread(addressData, sizeData, numbersData, pointerToFile);
```

* * *

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

```c
#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");

       // Program exits if the file pointer returns 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`记录到结构`num`中。

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

* * *

## 使用`fseek()`获取数据

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

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

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

* * *

### `fseek()`的语法

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

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

`fseek()`中的不同`whence`

| `whence` | 含义 |
| --- | --- |
| `SEEK_SET` | 从文件开头开始偏移。 |
| `SEEK_END` | 从文件末尾开始偏移。 |
| `SEEK_CUR` | 从文件中光标的当前位置开始偏移。 |

* * *

### 示例 5：`fseek()`

```c
#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");

       // Program exits if the file pointer returns NULL.
       exit(1);
   }

   // Moves the cursor to the end of the file
   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`中读取记录并进行打印。