C语言实现文件读写操作的几种常用方法

 更新时间:2024年03月07日 10:08:43   作者:dlpmmk  
C语言提供了一系列文件操作函数,使得我们可以通过程序对文件进行读写操作,本文主要介绍了C语言实现文件读写操作的几种常用方法,具有一定的参考价值,感兴趣的可以了解一下

一 、文件读写的常用函数

(1) 读写文本文件:

读文本文件 :一般都使用 getc 、fgets 、fscanf 函数

使用getc读文件

#include <stdio.h>
int main()
{
    char a[20] = "a.txt";
    FILE *p = fopen(a,"r");
    if(p)
    {
        char c;
        while(1)
        {
            c = getc(p);
            if(c == EOF)
                break;
            printf("%c",c);
        }
        printf("\n");
        fclose(p);
    }
    else
    {
        printf("fail\n");
    }
    return 0;
}

使用fgets读文件

#include <stdio.h>
int main()
{
    FILE *p = fopen("test.txt","r");
    if(p == NULL)
        return 0;
    char temp[1024];
    fgets(temp,sizeof(temp),p);
    while(!feof(p))
    {
        printf("%s",temp);
        fgets(temp,sizeof(temp),p);
    }
    fclose(p);
    return 0;
}

使用fscanf读文件

#include <stdio.h>
int main()
{
    FILE *p = fopen("a.txt", "r");
    if(p == NULL)
    {
        printf("the file is close!");
        return 0;
    }
    char str1[200], str2[200], str3[200];
    int year;
    int status = fscanf(p, "%s %s %s %d", str1, str2, str3, &year); 
    while(!feof(p))
    {
        printf("%s %s %d %d status = %d\n", str1, str2, str3, year, status);
        status = fscanf(p, "%s %s %s %d", str1, str2, str3, &year);
    }
    fclose(p);
    return 0;
}

写文本文件 :一般都使用 putc 、 fputs、fprintf 函数

使用putc写文件

#include <stdio.h>
int main()
{
    FILE *p = fopen("a.txt","w");
    if(p)
    {
        putc('h',p);
        fclose(p);
    }
    return 0;
}

使用fputs写文件

#include <stdio.h>
int main()
{
    FILE *p = fopen("abc.c","w");
    if(p)
    {
        fputs("#include <stdio.h>\nint main()\n{\nprintf(\"hello world\\n\");\nreturn 0;\n}",p);
        fclose(p);
    }
    return 0;
}

使用fprintf写文件

#include <stdio.h>
#include <string.h>
int main()
{
    FILE *p = fopen("a.txt","w");
    char buf[1024];
    fgets(buf, sizeof(buf), stdin);
    while(strcmp(buf,"exit\n") != 0)
    {
       fprintf(p, "%s", buf);
       fgets(buf, sizeof(buf), stdin); 
    }
    fclose(p);
    return 0;
}

(2) 读写二进制文件

读二进制文件: 使用fread 函数

代码:

#include <stdio.h>
void readFile()
{
    FILE *p = fopen("a.txt", "rb");
    char buf[20] = { 0 };
    int index = 0;
    while(1)
    {
        int res = fread(buf, 1, 5, p);
        printf("res = %d , ", res);
        if(feof(p))
            break;
        printf("buf = %s\n",buf);
        index++;
    }
    fclose(p);
    printf("%d\n", index);
}
int main()
{
    readFile();
    return 0;
}

写二进制文件: 使用fwrite 函数

代码

#include <stdio.h>
void writeFile()
{
    FILE *p = fopen("b.txt", "w");
    char buf = 'a';
    int i;
    for(i = 0; i < 10 ; i++)
    {
        fwrite(&buf, 1, 1, p);
        buf++;
    }
    fclose(p);
}
int main()
{
    writeFile();
    return 0;
}

二、文件读写的深层次的剖析

(1)操作系统与硬件储存

众所周知,我们的计算机操作系统都是由C语言写的,通过C语言协调物理内存与虚拟内存,操作系统想要向物理内存中写数据的时候,会费很大的力。

写数据到物理内存

当操作系统有一个字节的数据想要写入物理磁盘中,首先要经历一下几个步骤:

  • 调用CPU的控制器,发出存储请求。
  • 控制器把将要存储的数据放入临时寄存器。
  • 查看总线是否被占用,请求总线控制。
  • 往地址总线发送将要使用的一个字节的空间指定。
  • 讲数据寄存器中数据发送到数据总线上,传输到先一步找到的物理地址。
  • 存储完毕,释放总线。

从磁盘中读数据

读数据的操作与写数据的操作正好相反,也是要经历总线请求与总线释放的过程。

总之,操作系统想要往磁盘中读写数据要经历很繁琐的过程。

(2)操作系统封装读写数据函数接口

每次操作系统与磁盘进行数据交互的时候,都会对CPU有一系列的操作指令,这些读写指令的合集就是读写函数,通过C语言实现这些读写函数再往外部抛出一系列的接口,就实现的读写数据的函数封装。

当用户想往磁盘中写入数据的时候只需要调用这些函数接口就行了。

然而这些函数都是针对最底层的数据存储操作,不利于计算机的操作性能提高,所以,有人就在这层函数的基础上再次进行封装,把性能更加好,更加优化的读写数据函数封装到C语言的标准库中。

在标准库中的读写数据函数,例如fwrite和fputs等等。它们不是每次写入一个字节数据就往物理磁盘中写入数据,而是利用函数在内存中开辟出一个固定大小的字节缓冲池,通过这个缓冲池,来实现数据的读与写。

(3)C语言中的数据缓冲池

C语言的所有读写函数,都会使用到数据缓冲池,无论是读数据操作,还是写数据操作,都会把数据临时存储到这里。

写数据

当我们使用C语言往文件中写入一个字节的数据的时候,会经历一下几个步骤:

  • 使用函数往目标文件中写入一个字节的数据。
  • 数据被存储在内存的数据缓冲池中。
  • 关闭要写入的文件。
  • 底层函数把缓冲池中的数据写入磁盘中。

从上面的步骤中可以看出我们的函数在执行到写入数据的操作的时候,数据并没有真正的写入到磁盘中,而是等到写入文件的操作结束的时候,才把数据缓冲池中的数据写入磁盘中。

同样的我们使用C语言读一个字节数据的时候,同样会经历一下步骤:

  • 打开要读的文件。
  • 底层函数从磁盘中读取满整个缓冲池的数据。
  • 关闭要读的文件。
  • 从缓冲池中读取要读取的字节数,剩余没用的数据不读。

缓冲池工作原理

当知道我们的所有读写操作都要进入缓冲池时,我们同样要知道缓冲池的工作原理。

  • 缓冲池有一定固定的大小
  • 缓冲池在进行读数据的操作时,如果要读取的数据字节小于缓冲池的大小,缓冲池会从磁盘中读取满整个缓冲池的数据,所以当每次读取的字节数过小,读取次数过多的时候,会减少访问实际磁盘的磁盘,增加程序运行的性能。
  • 缓冲池的刷新,每刷新一次都会进行与实际物理内存的交互。

当缓冲池满了或者目标操作文件关闭的时候,缓冲池会自动刷新,写数据时,缓冲池的数据会进入物理磁盘;读数据时,缓冲池的数据会数据固定字节的数据进入输出终端。

总而言之,缓冲池仅仅是用户与物理磁盘之间数据交户的一个缓冲而已,不用想的太深奥。

三、使用函数刷新缓冲池

fflush函数:

函数作用:

刷新缓冲池

函数定义:

int fflush(FILE *P);

参数 返回值:

  • P:目标操作文件
  • 返回值:如果成功,该函数返回零值。如果发生错误,则返回 EOF 。

使用示例:

现有空文件a.txt

利用标准输入数据,在文件没有关闭的时候,查看文件内是否有写入的数据。

#include <stdio.h>
#include <string.h>
void write_file()
{
    FILE *p = fopen("a.txt", "w");
    char temp[100] = { 0 };
    while(1)
    {
        fgets(temp, sizeof(temp), stdin);
        if(strcmp(temp, "exit\n") == 0)
            break;
        fprintf(p, "%s", temp);
    }
    fclose(p);
}
int main()
{
    write_file();
    return 0;
}

运行结果:

输入中

[文件]$ gcc -o a fflush.c
[文件]$ a
hello

查看文件a.txt

可以看到文件为空,输入的文件现在正存储在缓冲池中。

输入exit退出输入,查看文件a

[文件]$ cat a.txt
hello

文件关闭,缓冲池中的数据写入磁盘。

现在我们创建一个函数使每输入一次都写入一次磁盘:

#include <stdio.h>
#include <string.h>
void write_file()
{
    FILE *p = fopen("a.txt", "w");
    char temp[100] = { 0 };
    while(1)
    {
        fgets(temp, sizeof(temp), stdin);
        if(strcmp(temp, "exit\n") == 0)
            break;
        fprintf(p, "%s", temp);
        fflush(p);
    }
    fclose(p);
}
int main()
{
    write_file();
    return 0;
}

运行结果:

输入中,查看a.txt

[文件]$ gcc -o a fflush.c
[文件]$ a
hello

再开启另一个终端查看文件 a.txt 状态:

[文件]$ cat a.txt
hello

输入结束,查看a.txt

[文件]$ a
hello
exit
[文件]$ cat a.txt
hello
[文件]$ 

可以看到使用fflush函数把缓冲池中的数据写入了磁盘。

四、总结

当我们在往磁盘中录入重要的非常重要的数据的时候,一定要使用fflush不断的刷新缓冲池,因为数据非常重要;但我们输入不重要的数据是一定要尽量减少使用fflush函数的次数,因为那样会让程序变得缓慢。

到此这篇关于C语言实现文件读写操作的几种常用方法的文章就介绍到这了,更多相关C语言 文件读写操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c语言线程终止练习示例

    c语言线程终止练习示例

    这篇文章主要介绍了c语言线程终止练习示例,需要的朋友可以参考下
    2014-04-04
  • VC获取当前路径及程序名的实现代码

    VC获取当前路径及程序名的实现代码

    VC上或取当前路径有多种方法,最常用的是使用 GetCurrentDirectory和GetModuleFileName函数,个中都有诸多注意事项,特别总结一下
    2016-11-11
  • C语言模拟实现strstr函数的示例代码

    C语言模拟实现strstr函数的示例代码

    strstr是C语言中的函数,作用是返回字符串中首次出现子串的地址。本文将用C语言模拟实现strstr函数,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-07-07
  • C++ STL入门教程(3) deque双向队列使用方法

    C++ STL入门教程(3) deque双向队列使用方法

    这篇文章主要为大家详细介绍了C++ STL入门教程第三篇,deque双向队列的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • C语言实现手写Map(全功能)的示例代码

    C语言实现手写Map(全功能)的示例代码

    这篇文章主要为大家详细介绍了如何利用C语言实现手写Map(全功能),文中的示例代码讲解详细,对我们学习C语言有一定帮助,需要的可以参考一下
    2022-08-08
  • C语言结构体内存对齐问题小结

    C语言结构体内存对齐问题小结

    本文主要讲解了C语言中结构体的内存对齐规则、计算方法以及影响因素,包括对齐规则的四个要点、内存对齐的原因、如何修改默认对齐数以及结构体传参时的注意事项,此外,还介绍了结构体位段的概念、内存分配和使用注意事项,感兴趣的朋友一起看看吧
    2025-02-02
  • C++实现俄罗斯方块游戏

    C++实现俄罗斯方块游戏

    这篇文章主要为大家详细介绍了C++实现俄罗斯方块游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • C++17中std::string_view的使用

    C++17中std::string_view的使用

    std::string_view是C++17标准库中的一种新类型,它提供了对一个字符序列的非拥有式视图,本文主要介绍了C++17中std::string_view的使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • c文件汇编后函数参数传递的不同之处

    c文件汇编后函数参数传递的不同之处

    在w7 32位系统下把c文件汇编后,确实与mac后的差异很大。可不仅仅是寄存器eax与rax的区别。我想说的是函数参数传递的不同
    2013-11-11
  • C语言详细分析讲解内存管理malloc realloc free calloc函数的使用

    C语言详细分析讲解内存管理malloc realloc free calloc函数的使用

    C语言内存管理相关的函数主要有realloc、calloc、malloc、free等,下面这篇文章主要给大家介绍了关于C语言内存管理realloc、calloc、malloc、free函数的相关资料,需要的朋友可以参考下
    2022-05-05

最新评论