【C语言进阶】文件的顺序读写、随机读写、文本文件和二进制文件、文件读取结束的判定以及文件缓冲区相关知识(中)

简介: 【C语言进阶】文件的顺序读写、随机读写、文本文件和二进制文件、文件读取结束的判定以及文件缓冲区相关知识(中)

完成后我们再用“ 读 ”模式打开该文件,并在判断非空后使用 fgetc 函数来顺序读取该文件中的内容:

int main()
{
  FILE* p = fopen("test.txt", "r");
  //文件打开模式为“读”
  if (p == NULL)
  {
    perror("FILE_OPEN");
    return 1;
  }
  int ch = 0;
  while ((ch = fgetc(p)) != EOF)
  {
    printf("%c ", ch);
    //顺序读取文件指针pp指向文件内的信息并打印
  }
  fclose(p);
  p = NULL;
  return 0;
}

将程序编译运行起来查看我们 fgetc 函数的读取结果eb36a65b84de4f579c231cb08e5ce14f.png并且我们也可以使用 fputs 函数(区别于 fputc 函数)来实现字符串的顺序写入:

int main()
{
  FILE* p = fopen("test.txt", "w");
  //文件打开模式为“写”
  if (p == NULL)
  {
    perror("FILE_OPEN");
    return 1;
  }
  fputs("The test TXT\n", p);
  //fputc 为写入字符,fouts 为写入字符串
  //只写入字符串内容,不会自动换行,想要换行需手动添加换行转义字符\n
  //并且在写入时,会覆盖原本的内容数据
  fputs("The test TXT", p);
  fclose(p);
  p = NULL;
  return 0;
}

或使用 fgets 函数(区别于 fgetc 函数)来实现字符串的顺序读取:

int main()
{
  FILE* p = fopen("test.txt", "r");
  //文件打开模式为“读”
  if (p == NULL)
  {
    perror("FILE_OPEN");
    return 1;
  }
  char arr[256] = { 0 };
  //定义字符数组用于存放读取到的字符串
  fgets(arr, 256, p);
  //从文件指针p指向文件处,读取最多256个字符,并将数据读取至字符数组arr中
  //该函数为按行读取,读取至换行转义符\n处主动停止并换行
  printf("%s", arr);
  //想要读取两行就需要使用两次fgets函数
  fgets(arr, 256, p);
  printf("%s", arr);
  fclose(p);
  p = NULL;
  return 0;
}

最终目的,就是要结合文件操作将数据保存至本地硬盘中,从而实现优化,于是我们可以使用 fprintf 函数实现将结构体变量的内容保存至本地硬盘之中:

typedef struct Contact
{
  char name[20];
  char sex[5];
  int age;
  char tele[11];
}con;
int main()
{
  FILE* p = fopen("test.txt", "w");
  //文件打开模式为“写”
  if (p == NULL)
  {
    perror("FILE_OPEN");
    return 1;
  }
  con c1 = { "Sherry","女",18,"3478290" };
  fprintf(p, "%s %s %d %s\n", c1.name, c1.sex, c1.age, c1.tele);
    //按照"%s %s %d %s\n"的格式将数据c1.name, c1.sex, c1.age, c1.tele写入至p所指向的文件内
  fclose(p);
  p = NULL;
  return 0;
}

程序编译运行结束后关闭,这时我们再去本地文件中查看会发现,数据已经成功的保存至本地硬盘中了:

cb9b5b9e6b404350af0341f69cc2fc82.png

并且我们也可以通过 fscanf 函数从本地硬盘文件中读取数据:

typedef struct Contact
{
  char name[20];
  char sex[5];
  int age;
  char tele[11];
}con;
int main()
{
  FILE* p = fopen("test.txt", "r");
  //文件打开模式为“读”
  if (p == NULL)
  {
    perror("FILE_OPEN");
    return 1;
  }
  con c1 = { 0 };
  fscanf(p, "%s %s %d %s", c1.name, c1.sex, &(c1.age), c1.tele);
  //按照"%s %s %d %s"的格式,从p所指向的文件中将数据读取至c1.name, c1.sex, &(c1.age), c1.tele中
  printf("%s %s %d %s\n", c1.name, c1.sex, c1.age, c1.tele);
  fclose(p);
  p = NULL;
  return 0;
}

c666fe053df340c09a99307a93e1153a.png

3. 文件随机读写:

我们很多时候并不是要进行顺序读写,而是进行随机读写(伪随机,指不按照顺序依次进行读写)。为了实现这样的操作,我们就需要使用 fseekftellrewind 三个函数来帮助我们对这样的操作进行实现。

3.1 fseek 函数:

fseek 函数的作用为,根据文件指针的位置和偏移量来定位文件指针。

int fseek(FILE* strname, long int offset, int origin);

1.“ offset”为相对于指针位置的指针偏移量

2.“ origin ”为指针位置,其参数有三种:“ SEEK_CUR ”表示文件指针当前位置;“ SEEK_END ”表示文件末尾的位置;“ SEEK_SET ”表示文件开始位置

int main()
{
  FILE* p = fopen("test.txt", "r+");
  //文件打开模式为“读写”
  if (p == NULL)
  {
    perror("FILE_OPEN");
    return 1;
  }
  char ch = 'a';
  for (ch = 'a'; ch <= 'z'; ch++)
  {
    fputc(ch, p);
    //使用 fputc 函数顺序写入小写字符a~z
  }
  fseek(p, 10, SEEK_SET);
  //使用fseek函数将文件指针从文件开始处(参数SEEK_SET表示文件起始位置)指向偏移量为10处
  //偏移量为正表示向后偏移,为负表示向前偏移
  char output;
  output = fgetc(p);
  //接下来进行读取时,继续向后读取一个字符,即字符k
  printf("%c\n", output);
  fclose(p);
  p = NULL;
  return 0;
}

f977e194454249c7ad2208e455361fb2.png

3.2 ftell 函数:

long int ftell(FILE* strname);
• 1

ftell 函数的作用为,返回文件指针相对于文件起始位置的偏移量。

int main()
{
  FILE* p = fopen("test.txt", "r+");
  //文件打开模式为“读写”
  if (p == NULL)
  {
    perror("FILE_OPEN");
    return 1;
  }
  char ch = 'a';
  for (ch = 'a'; ch <= 'z'; ch++)
  {
    fputc(ch, p);
    //使用 fputc 函数顺序写入小写字符a~z
  }
  fseek(p, -5, SEEK_END);
  //使用fseek函数将文件指针从文件结尾处(参数SEEK_SET表示文件起始位置)指向偏移量为-5处
  //偏移量为正表示向后偏移,为负表示向前偏移
  long back = ftell(p);
  //定义整型变量用于接受并记录指针相对于起始位置的偏移量
  printf("指针相对于起始位置的偏移量为:%ld\n", back);
  fclose(p);
  p = NULL;
  return 0;
}

ea4d50a4b88046389c62f6dc4a6079e8.png

3.3 rewind 函数:

void rewind(FILE* strname);

rewind 函数的作用为,使文件指针位置返回文件的起始位置

int main()
{
  FILE* p = fopen("test.txt", "r+");
  //文件打开模式为“读写”
  if (p == NULL)
  {
    perror("FILE_OPEN");
    return 1;
  }
  char ch = 'a';
  for (ch = 'a'; ch <= 'z'; ch++)
  {
    fputc(ch, p);
    //使用 fputc 函数顺序写入小写字符a~z
  }
  fseek(p, -5, SEEK_END);
  rewind(p);
  //使文件指针回归文件起始位置
  printf("%c\n", fgetc(p));
  //打印验证指针当前位置
  fclose(p);
  p = NULL;
  return 0;
}

76b78845340e49e48df9a8bd047af72b.png

4. 文本文件与二进制文件:

根据数据的组织形式,我们将数据文件称为文本文件二进制文件

二进制文件:在我们的计算机内存中,各种数据都是以二进制码的形式进行存储的,以 二进制码形式进行存储的文件

文本文件:以 ASCII 字符形式进行存储的文件

如果我们想要在外存上以 ASCII 码的形式存储数据,就需要在存储前将数据进行转换。

数据在内存中数据到底是如何让进行存储的呢?

实际上,字符在内存中的存储一律是以 ASCII 码的形式进行存储的,而数值型数据既可以用ASCII 码存储,也可以用二进制形式进行存储。

例如十进制数字 10000 在进行存储时,就可以有两种存储形式:

1.二进制形式:

00000000 00000000 00100111 00010000

2.ASCII码形式:

00110001 00110000 00110000 00110000 000110000

1 0 0 0 0


int main()
{
  int a = 10000;
  FILE* p = fopen("test.txt", "wb");
  //“wb”表示以只写模式打开二进制文件
  if (p == NULL)
  {
    perror("FileOpen");
    return 0;
  }
  fwrite(&a, 4, 1, p);
  //将变量a中的数据,每四个字节存储一次,写入文件指针p所指向的文件
  fclose(p);
  p = NULL;
  return 0;
}

在上面这段代码运行成功后,我们已经成功的将变量 a 中的数据写入到了本地磁盘对应的 txt 文件中了,可是我们发现,当我们尝试打开本地文件查看存储的数据时,里面看起来并不是我们想要的结果:

005629e48a8f486d8ce1182a2936b8b4.png

相关文章
|
11天前
|
存储 小程序 C语言
【C语言程序设计——文件】文件操作(头歌实践教学平台习题)【合集】
本文介绍了C语言中的文件操作,分为两个关卡。第1关任务是将键盘输入的字符(以#结束)存入`file1.txt`并显示输出;第2关任务是从键盘输入若干行文本(每行不超过80个字符,用-1作为结束标志),写入`file2.txt`后再读取并显示。文中详细讲解了文件的打开、读取(使用`fgetc()`和`fgets()`)、写入(使用`fputc()`和`fputs()`)及关闭操作,并提供了示例代码和测试说明。
29 5
|
2月前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
179 3
|
3月前
|
存储 编译器 C语言
如何在 C 语言中判断文件缓冲区是否需要刷新?
在C语言中,可以通过检查文件流的内部状态或使用`fflush`函数尝试刷新缓冲区来判断文件缓冲区是否需要刷新。通常,当缓冲区满、遇到换行符或显式调用`fflush`时,缓冲区会自动刷新。
|
3月前
|
存储 编译器 C语言
C语言:文件缓冲区刷新方式有几种
C语言中文件缓冲区的刷新方式主要包括三种:自动刷新(如遇到换行符或缓冲区满)、显式调用 fflush() 函数强制刷新、以及关闭文件时自动刷新。这些方法确保数据及时写入文件。
|
C语言 数据处理
C语言及程序设计进阶例程-37 二进制文件及其读写
贺老师教学链接 C语言及程序设计进阶 本课讲解 对比ASCII文件和二进制文件 //(1)将short int x=12321写入文本文件 #include&lt;stdio.h&gt; #include&lt;stdlib.h&gt; int main( ) { short int x=12321; FILE *outfile = fopen("as
1149 0
|
11天前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
49 23
|
11天前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
41 15
|
11天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
50 24
|
7天前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
46 16
|
6天前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
18 3

热门文章

最新文章