高阶C语言|文件操作——你不知道的文件小秘密

欢迎讨论:在阅读过程中有任何疑问,欢迎在评论区留言,我们一起交流学习!
点赞、收藏与分享:如果你觉得这篇文章对你有帮助,记得点赞、收藏,并分享给更多对C语言感兴趣的朋友

文章目录

        • 文件,究竟是什么鬼?
        • 文件指针——你的文件“朋友”
        • 文件打开的那些“门道”
        • 常用的顺序输入输出函数——让你有条不紊的使用文件
        • 流的含义——数据的“大马路”
        • fseek和ftell——让你随意“跳跃”文件
        • rewind——倒带重放,穿越回文件的“起点”
        • 文件缓冲区——它的幕后“神操作”
        • 文件读取结束的判定——别让它“赖账”
        • 总结:文件不再神秘

文件,究竟是什么鬼?

说到文件,大部分人可能会想:“哎呀,不就是那种看得见摸得着的东西嘛!”没错,文件就是磁盘上的一堆信息,只不过它们的样子不太一样。比如有程序文件(扩展名 .c.exe 什么的)和数据文件(它们存储的是你在程序里使用的数据)。别看这些文件表面平凡,它们的背后可是大有文章。

我们常见的文件有两大类:

  1. 程序文件:这些通常是你的源代码文件(像 .c 后缀的文件),以及编译后产生的目标文件(例如 .obj.exe)。这类文件代表的是程序的执行逻辑和操作。
  2. 数据文件:这些文件是程序运行过程中需要的外部数据,或者是程序执行后的输出结果。

文件本身并不复杂,了解了这些,你就能轻松搞定文件操作。

文件指针——你的文件“朋友”

文件操作不可能不提文件指针。你和文件的每次互动,都得有个“桥梁”——这就是文件指针。它就像是你和文件沟通的一个小助手,通过它,你可以告诉文件“嘿,快给我读点东西”,或者“你可以关机啦”。不信?来看看下面这段代码:

FILE* fp = fopen("myfile.txt", "w");

这个 fp 变量就是文件指针,它让你能够连接到文件 myfile.txt,然后对它进行各种操作。想关上它吗?那就用 fclose 把它“请走”:

fclose(fp);
fp = NULL; // 防止野指针乱来

通过文件指针,你可以在内存中找到文件的相关信息(如文件名、文件状态等),也可以方便地进行读取或写入操作。

文件打开的那些“门道”

打开文件有一堆方式,比如只读、只写、追加等等。就像你去餐厅点菜,有的人喜欢点个“只读的沙拉”,有的人则想要一份“只写的牛排”。不过,要记住,一旦选定了“门道”,就不能乱点其他的了!

打开文件的方式有很多种,主要有以下几种模式:

文件使用方式 含义 如果指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错
“w”(只写) 为了输入数据,打开一个文本文件 建立一个新文件
“a”(追加) 向文本文件尾添加数据 建立一个新文件
“rb”(只读) 为了输入数据,打开一个二进制文件 出错
“wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新文件
”ab“ 向一个二进制文件尾添加数据 出错

例如,你想打开一个文件并向其中写入内容,可以使用以下代码:

#include 
int main ()
{
 FILE * pFile;
 //打开文件
 pFile = fopen ("myfile.txt","w");
 //文件操作
 if (pFile != NULL)
{
  fputs ("fopen example", pFile);
  //关闭文件
  fclose (pFile);
}
 return 0;
}
常用的顺序输入输出函数——让你有条不紊的使用文件
  1. 字符输入函数(fgetc)

    • 函数名称fgetc
    • 适用流:所有输入流
    • 功能fgetc 用于从文件中读取一个字符。无论是从标准输入流(如键盘)还是文件流,它都可以读取字符。
  2. 字符输出函数(fputc)

    • 函数名称fputc
    • 适用流:所有输出流
    • 功能fputc 用于将一个字符写入文件,或者输出到其他流(如标准输出流)。
  3. 文本行输入函数(fgets)

    • 函数名称fgets
    • 适用流:所有输入流
    • 功能fgets 用于从文件中读取一行文本,通常用于处理每行数据时,比 fgetc 更加方便,因为它能读取整行数据。
  4. 文本行输出函数(fputs)

    • 函数名称fputs
    • 适用流:所有输出流
    • 功能fputs 将一行文本写入文件或者输出流,适合写入字符串。
  5. 格式化输入函数(fscanf)

    • 函数名称fscanf
    • 适用流:所有输入流
    • 功能fscanf 是一个格式化输入函数,类似于 scanf,用于从文件中读取格式化的数据(如整数、浮点数、字符串等)。
  6. 格式化输出函数(fprintf)

    • 函数名称fprintf
    • 适用流:所有输出流
    • 功能fprintf 是一个格式化输出函数,类似于 printf,可以将格式化的输出写入文件或其他流。
  7. 二进制输入(fread)

    • 函数名称fread
    • 适用流:文件
    • 功能fread 用于从文件读取二进制数据,这与从文件读取文本数据不同,适用于处理二进制文件。
  8. 二进制输出(fwrite)

    • 函数名称fwrite
    • 适用流:文件
    • 功能fwrite 用于将二进制数据写入文件,常用于文件格式为二进制的应用。
流的含义——数据的“大马路”

图中的流指的是数据流向的方向,简而言之,流就像一个通道,通过它,程序可以与不同的数据源(如文件、标准输入/输出、网络)进行数据交换。

  • 标准输入流(stdin):表示从键盘或者其他输入设备获取数据。类型为 FILE*
  • 标准输出流(stdout):表示向屏幕或终端输出数据,也常用于程序的输出。类型为 FILE*
  • 标准错误流(stderr):专门用来输出错误信息,通常输出到屏幕,帮助调试和记录错误。类型为 FILE*

这些流在 C 语言中有默认的设置,你可以使用它们来与程序外部的数据进行交互。

fseek和ftell——让你随意“跳跃”文件

如果文件指针是你和文件之间的“通信员”,那 fseekftell 就是你用来“调皮捣蛋”的工具。想要快速跳转到文件的某个位置?fseek 就是你的“跳跃王者”。它能让你精准地告诉文件:“嘿!快点,跳到那个地方!”

fseek(fp, 100, SEEK_SET); // 跳到文件的第100个字节

如果你是个数字控,ftell 会告诉你文件指针现在在第几字节,完美配合使用,你就能像个文件专家一样随心所欲地翻阅文件。

long int position = ftell(fp);
printf("Current position: %ld\n", position);

有了它们,文件就像一张无穷无尽的地图,而你是那个能够自由穿梭的探险家。

rewind——倒带重放,穿越回文件的“起点”

偶尔我们会在文件中“迷失”,对吧?但别担心,rewind 函数会帮你找回“方向感”,它能把文件指针迅速拉回文件的起点,仿佛你按下了“倒带”按钮,所有操作都能重新开始。

rewind(fp); // 把文件指针拉回到开头

是不是感觉像是时光机?你可以重新阅读文件的内容,或者再次执行某些操作,完全不需要重开一个新文件。

文件缓冲区——它的幕后“神操作”

当你和文件在“亲密互动”的时候,文件并不总是立刻回应你。为什么?因为文件背后有一个隐秘的“缓冲区”,这个缓冲区可不是随便的东西,它像是个内存仓库,存储着所有待操作的数据。系统会先把数据传递到缓冲区,再从缓冲区读取或写入磁盘。你可能觉得它不够直接,但这也让整个过程更高效。

不过,既然是“幕后工作”,它就不喜欢被打扰。如果你不小心忽略了这个缓冲区的刷新(比如直接关闭文件),数据可能就会丢失。所以,记得及时调用 fflush 来刷新缓冲区,确保文件内容没跑掉:

fflush(fp); // 刷新缓冲区,确保数据写入文件
文件读取结束的判定——别让它“赖账”

当你和文件打交道时,总会遇到“结束”的问题。你是不是也曾经遇到过文件读到一半就突然消失的情况?别怕,文件结束有专门的信号,比如 EOF(文件结束符)或者 NULL(读取错误)。当你遇到这些信号时,表示文件已经结束或发生了错误,赶紧收拾收拾,不要继续“纠缠”下去。

文本文件的读取可以使用 fgetc 来判断是否遇到 EOF,或者用 fgets 判断返回值是否为 NULL,这都能告诉你文件是否正常结束。

对于二进制文件,我们则需要注意 fread 的返回值,它能告诉你是否成功读取了预期的字节数。

#include 
#include 
int main(void)
{
  int c; // 注意:int,非char,要求处理EOF
  FILE* fp = fopen("test.txt", "r");
  if(!fp) {
    perror("File opening failed");
    return EXIT_FAILURE;
 }
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
  while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
 {
   putchar(c);
 }
 //判断是什么原因结束的
  if (ferror(fp))
    puts("I/O error when reading");
  else if (feof(fp))
    puts("End of file reached successfully");
  fclose(fp);
}
总结:文件不再神秘

文件操作的世界其实并没有你想象的那么复杂。只要掌握了文件打开、读写、关闭的基本技巧,再加上对 fseekrewind 这些“小工具”的灵活运用,你就能轻松自如地管理你的文件了。

所以,下次当你面对文件时,不要再紧张了!只要记得好好地与它互动,文件也会变成你忠实的小伙伴,陪你一起完成各种任务,轻松搞定所有挑战。


你可能感兴趣的:(C语言篇,c语言,前端,java)