C语言详解 FILE文件操作

2023-05-16

1. 需要了解的概念

需要理解的知识点包括:数据流、缓冲区、文件类型、文件存取方式
 

1.1 数据流:

指程序与数据的交互是以流的形式进行的。进行C语言文件的存取时,都会先进行“打开文件”操作,这个操作就是在打开数据流,而“关闭文件”操作就是关闭数据流。

1.2 缓冲区(Buffer):

指在程序执行时,所提供的额外内存,可用来暂时存放做准备执行的数据。它的设置是为了提高存取效率,因为内存的存取速度比磁盘驱动器快得多。

 C语言中带缓冲区的文件处理:

C语言的文件处理功能依据系统是否设置“缓冲区”分为两种:一种是设置缓冲区,另一种是不设置缓冲区。由于不设置缓冲区的文件处理方式,必须使用较低级的I/O函数(包含在头文件io.h和fcntl.h中)来直接对磁盘存取,这种方式的存取速度慢,并且由于不是C的标准函数,跨平台操作时容易出问题。下面只介绍第一种处理方式,即设置缓冲区的文件处理方式:

当使用标准I/O函数(包含在头文件stdio.h中)时,系统会自动设置缓冲区,并通过数据流来读写文件。当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据,如下图所示:

事实上,当写入文件时,并不会马上写入磁盘中,而是先写入缓冲区,只有在缓冲区已满或“关闭文件”时,才会将数据写入磁盘,如下图所示。


1.3 文件类型:

分为文本文件和二进制文件两种。

文本文件是以字符编码的方式进行保存的。二进制文件将内存中数据原封不至文件中,适用于非字符为主的数据。如果以记事本打开,只会看到一堆乱码。

其实,除了文本文件外,所有的数据都可以算是二进制文件。二进制文件的优点在于存取速度快,占用空间小,以及可随机存取数据。
 

1.4 文件存取方式:

包括顺序存取方式和随机存取方式两种。

顺序读取也就是从上往下,一笔一笔读取文件的内容。保存数据时,将数据附加在文件的末尾。这种存取方式常用于文本文件,而被存取的文件则称为顺序文件。

随机存取方式多半以二进制文件为主。它会以一个完整的单位来进行数据的读取和写入,通常以结构为单位。


2. 文本文件操作

C语言中主要通过标准I/O函数来对文本文件进行处理。相关的操作包括打开、读写、关闭与设置缓冲区。
相关的存取函数有:fopen(), fclose(), fgetc(), fputc(), fgets(), fputs(), fprintf(), fscanf()等。
 

2.1 打开文件

函数原型为:_CRTIMP FILE * __cdecl fopen(const char *, const char *);

第一参数为文件名,第二个参数为打开模式。

打开成功,fopen返回一个结构指针地址,否则返回一个NULL。如果没有指定文件路径,则默认为当前工作目录。如:

FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r") //由于反斜杠\是控制字符,所以必须再加一个反斜杠

使用fopen()函数打开的文件会先将文件复制到缓冲区。注意:所下达的读取或写入动作,都是针对缓冲区进行存取而不是磁盘,只有当使用fclose()函数关闭文件时,缓冲区中的数据才会写入磁盘。
 

  谈文件打开模式

打开文本文件:

"r":只能从文件中读数据,该文件必须先存在,否则打开失败
"w":只能向文件写数据,若指定的文件不存在则创建它,如果存在则先删除它再重建一个新文件
"a":向文件增加新数据(不删除原有数据),若文件不存在则打开失败,打开时位置指针移到文件末尾
"r+":可读/写数据,该文件必须先存在,否则打开失败
"w+":可读/写数据,用该模式打开新建一个文件,先向该文件写数据,然后可读取该文件中的数据
"a+":可读/写数据,原来的文件不被删去,位置指针移到文件末尾

打开二进制文件的模式与打开文本文件的含义是一样的,不同的是模式名称里面多一个字母'b’,以表示以二进制形式打开文件。
 

2.2 关闭文件

函数原型为:_CRTIMP int __cdecl fclose(FILE *);

关闭成功返回值0,否则返回非零值。

注:在执行完文件的操作后,要进行“关闭文件”操作。虽然程序在结束前会自动关闭所有的打开文件,但文件打开过多会导致系统运行缓慢,这时就要自行手动关闭不再使用的文件,来提高系统整体的执行效率。

例1. 打开文件并进行判断和关闭文件

FILE *fp;
fp = fopen("c:\\temp\\test.txt", "r");

if(fp == NULL)
    printf("fail to open the file! \n");
else
{
    printf("The file is open! \n");
    fclose(fp);
}

2.3 字符存取函数

函数原型为:

_CRTIMP int __cdecl fputc(int, FILE *);
_CRTIMP int __cdecl fgetc(FILE *);

字符读取函数fgetc()可从文件数据流中一次读取一个字符,然后读取光标移动到下一个字符,并逐步将文件的内容读出。

如果字符读取成功,则返回所读取的字符,否则返回EOF(end of file)。EOF是表示数据结尾的常量,真值为-1。另外,要判断文件是否读取完毕,可利用feof()进行检查。未完返回0,已完返回非零值。

feof()函数原型为:_CRTIMP int __cdecl feof(FILE *);

例2. fgetc()函数的使用

版本1:利用feof()函数检查文件是否读取完毕

#include <stdio.h>

main()
{
    FILE *fp;
    fp = fopen("c:\\temp\\test.txt", "r");
    if(fp != NULL)
    {
        while(!feof(fp))
            printf("%c", fgetc(fp));
    }
    else
        printf("fail to open! \n");
    fclose(fp);

    return 0;
}


版本2:利用文件结束标志EOF(即-1)

#include <stdio.h>

main()
{
    char ch;
    FILE *fp;
    fp = fopen("c:\\temp\\test.txt", "r");
    if(fp != NULL)
    {
        ch = fgetc(fp);
        while(ch != EOF)
        {
            putchar(ch);
            ch = fgetc(fp);
        }

    }
    else
        printf("fail to open! \n");
    fclose(fp);

    return 0;
}


版本3 - 重构版本2

#include <stdio.h>

main()
{
    char ch;
    FILE *fp;
    if((fp = fopen("test.txt", "r")) != NULL)
        while((ch = fgetc(fp)) != EOF)
            putchar(ch);
    else
        printf("fail to open! \n");
    fclose(fp);

    return 0;
}


版本4 - 重构版本3 (不正确的重构)

#include <stdio.h>

main()
{
    FILE *fp;
    if((fp = fopen("test.txt", "r")) != NULL)
        while(fgetc(fp) != EOF)
            putchar(fgetc(fp));
    else
        printf("fail to open! \n");
    fclose(fp);

    return 0;
}



若要将字符逐一写入文件,用fputc()函数。示例为:

例3. fputc()函数的使用

#include <stdio.h>
#include <conio.h>

main()
{
    char filename[20], ch;
    FILE *fp;
    printf("Enter a filename: ");
    scanf("%s", filename);
    printf("Enter some characters to output to file: ");
    if((fp = fopen(filename, "w")) == NULL)
        printf("fail to open! \n");
    else
    {
        while((ch = getche()) != '\015')
            fputc(ch, fp);
    }
    fclose(fp);

    return 0;
}


 

2.4 字符串存取函数

函数原型为:

_CRTIMP int __cdecl fputs(const char *, FILE *);
_CRTIMP char * __cdecl fgets(char *, int, FILE *);

fgets函数的作用是从指定文件读入一个字符串,如:fgets(str, n, fp);

参数n为要求得到的字符个数,但只从fp指向的文件输入n-1个字符,然后在最后加一个'\0'字符,因此得到的字符串共有n个字符,把它们放在字符数组str中。如果在读完n-1个字符之前遇到换行符或EOF,读入结束。

fputs函数的作用是向指定文件输出一个字符串,如:fputs("Hey", fp);

把字符串"Hey"输出到fp指向的文件。fputs函数的第一个参数可以是字符串常量、字符数组名或字符型指针。若输出成功,则返回0,否则返回EOF。

实例略

2.5 格式化存取函数

函数原型为:

_CRTIMP int __cdecl fprintf(FILE *, const char *, ...);
_CRTIMP int __cdecl fscanf(FILE *, const char *, ...);

它们与printf和scanf函数相仿,都是格式化读写函数。不同的是:fprintf和fscanf函数的读写对象不是终端(标准输入输出),而是磁盘文件。printf函数是将内容输出到终端(屏幕),因此,fprintf就是将内容输出到磁盘文件了。

实例4. fprintf和fscanf函数的使用

#include <stdio.h>

void main()
{
    FILE *fp;

    int num = 10;
    char name[10] = "Leeming";
    char gender = 'M';

    if((fp = fopen("info.txt", "w+")) == NULL)
        printf("can't open the file! \n");
    else
        fprintf(fp, "%d, %s, %c", num, name, gender); //将数据格式化输出到文件info.txt中

    fscanf(fp, "%d, %s, %c", &num, name, &gender); //从文件info.txt中格式化读取数据
    printf("%d, %s, %c \n", num, name, gender); //格式化输出到屏幕

    fclose(fp);
}


 

2.6 指针重返函数

函数原型为:

_CRTIMP void __cdecl rewind(FILE *);;

rewind函数的作用是使位置指针重返回文件的开头,属于文件的定位。

3. 二进制文件操作

3.1 数据块存取函数

函数原型:

_CRTIMP size_t __cdecl fread(void *, size_t, size_t, FILE *);
_CRTIMP size_t __cdecl fwrite(const void *, size_t, size_t, FILE *);

当要求一次存取一组数据(如,一个数组、一个结构体变量的值),fread和fwrite函数可以解决该类问题。它们的调用形式一般为:

fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);

buffer:对于fread来说,指的是读入数据的存放地址;对于fwrite来说,是要输出数据的地址。
size:读写数据时,每笔数据的大小
count:读写数据的笔数
fp:文件指针
 

实例5. fread和fwrite函数的使用

#include <stdio.h>
#define SIZE 3

typedef enum { MM, GG } Gender;

typedef struct
{
    char name[10];
    int  age;
    Gender gender;
} Person;

void write2file(Person emp[SIZE])
{
    FILE *fp;
    if((fp = fopen("emp.txt", "wb")) == NULL)
    {
        printf("cannot open file! \n");
        return;
    }

    for(int i=0; i<SIZE; i++)
        if(fwrite(&emp[i], sizeof(Person), 1, fp) != 1)
            printf("file write error! \n");
    fclose(fp);
}

void read_from_file(FILE *fp)
{
    Person emp_out[SIZE];

    if((fp = fopen("emp.txt", "rb")) == NULL)
    {
        printf("cannot open file! \n");
        return;
    }

    printf("\n%d employee's information read: \n", SIZE);

    for(int i=0; i<SIZE; i++)
    {
        if(fread(&emp_out[i], sizeof(Person), 1, fp) != 1)
            if(feof(fp))
            {
                fclose(fp);
                return;
            }
            printf("%-5s %4d %5d \n", emp_out[i].name, emp_out[i].age, emp_out[i].gender);
    }
    fclose(fp);
}

void main()
{
    FILE *fp = NULL;
    Person employee[SIZE];

    printf("Enter %d employee's information: \n", SIZE);
    for(int i=0; i<SIZE; i++)
        scanf("%s %d %d", employee[i].name, &employee[i].age, &employee[i].gender);

    write2file(employee);

    read_from_file(fp);
}


 

3.2 随机存取函数fseek()

函数原型:

_CRTIMP int __cdecl fseek(FILE *, long, int);

对流式文件可以进行顺序读写,也可以进行随机读写。关键在于控制文件的位置指针,如果位置指针是按字节位置顺序移动的,就是顺序读写。如果能将位置指针按需要移动到任意位置,就可以实现随机读写。所谓随机读写,是指读完上一个字符(字节)后,并不一定要读写其后续的字符(字节),而可以读写文件中任意位置上所需要的字符(字节)。该函数的调用形式为:

fseek(fp, offset, start);

start:起始点。用0、1、2代替。0代表文件开始,名字为SEEK_SET,1代表当前位置,名字为SEEK_CUR,2代表文件末尾,名字为SEEK_END。

fseek()函数一般用于二进制文件,因为文本文件要发生字符转换,计算位置时往往会发生混乱。

调用实例如:

fseek(fp, i*sizeof(Person), 0);

C语言详解 FILE文件操作_yong_sun的博客-CSDN博客_c语言nfileend

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言详解 FILE文件操作 的相关文章

  • 使用java在mysql中插入带有\\的文件路径

    我正在使用java制作一个独立的应用程序 并且我需要插入用户从文件选择器中选择的图像的路径 我正在获取文件的路径 但是当我将其存储在数据库 mysql 中时 它不会存储 所以当我检索该路径时 该文件不会显示 如何存储文件的路径 这样就可以使
  • iPhone 存储图像的最佳方式

    我正在开发一个应用程序 需要缓存一些来自网络的图像 图像可能是 100x100 我只需要知道哪个更好 将图像作为文件存储在 iPhone 文件系统中 将它们作为 blob 与已保存在数据库中的其他数据一起存储在 sqlite 数据库中 感谢
  • php同时上传最大文件数

    我正在使用标签 用于使用 php 上传多个文件 我注意到 如果我选择超过 20 个文件 php 只会上传前 20 个文件 有没有办法扩大这个限制 这个限制被添加到PHP 5 2 12 https www php net releases 5
  • 如何获取文件的 ctime、atime、mtime 并更改它们

    如何使用 Go 获取文件的 ctime mtime atime 并更改它们 在 Go 1 1 2 中 os Stat只能获取mtime os Chtimes 可以更改 mtime 和 atime 但不能更改 ctime Linux ctim
  • 使用python删除未访问的文件

    My django app解析用户上传的一些文件 用户上传的文件可能会在服务器中保留很长时间 而没有被应用程序解析 如果很多用户上传大量文件 这可能会增加大小文件 我需要删除应用程序最近未解析的那些文件 比如not accessed for
  • Nginx Node.js 快速下载大文件止于 1.08GB

    我有这个由 Nginx 代理的 Node js 应用程序 在生产环境中 路线是这样的 exports download function req res var id req params id if id id latest res do
  • 如何突出显示2个html文件之间的差异

    我的网络应用程序有职位描述 某些用户可以修改这些职位描述 每次修改都会产生新版本的职位描述 职位描述的内容由用户使用tinymce 编辑器直接在textarea 中以html 形式进行编辑 我希望能够向用户展示内容从一个版本到另一个版本所做
  • 如何将 .wav 文件转换为字节数组?

    我有一个 wav我的磁盘驱动器中的文件 我需要转换它 wav文件至byte array使用java 有人可以帮忙吗 您可以使用Files readAllBytes http docs oracle com javase 7 docs api
  • 从多个进程附加到单个文件的“线程安全”?

    假设我有 X 个进程打开文件 Y 进行追加 每个进程一次只写入一行 带有 n 真正的日志条目 文件 Y 中的每一行是否保证不会错误地交错 更新 本地附加文件系统 问题取决于正在进行什么类型的写入 如果您使用带缓冲的标准 I O 这通常是大多
  • python - 使用“with”语句后的变量范围[重复]

    这个问题在这里已经有答案了 我在 stackoverflow 上没有找到这个问题的答案 所以我认为询问它可能会有所帮助 并将其放在这里 我在打开文件后声明一个新字典 方法如下 with open some file txt r as f d
  • 比较方法在对文件进行排序时违反了其一般契约

    我知道这种异常有很多问题 而且我确实找到了解决方案 但我的问题是不同项目中的相同代码不会抛出异常 而这个却抛出异常 这两个项目都具有相同版本的 Java 和其他库 基本上我有一个小函数 它从目录中检索文件列表 按时间戳对它们进行排序 然后返
  • 使用桌面的默认应用程序打开存储在 jar 文件中的 PDF 文件

    我的计算机科学课程的程序开发即将结束 然而 要求之一是应用程序内有一份用户手册 我在 Eclipse 工作区中将用户手册保存为 PDF 它存储在 Documents PDF Manual pdf 下 我最初使用这段代码 URL url ge
  • getExternalCacheDir() 在 Android 上如何工作?

    据我了解 我们将经常访问的对象缓存在比普通磁盘读取更容易访问的内存段中 getExternalCacheDir 相对于getCacheDir 指向外部文件系统 在我看来这是正常的getExternalFilesDir Android 如何优
  • 读取多个文件 cotent 的 React JS

    我正在尝试使用 React js 读取多个文件 但我的代码只读取一个文件 而不会读取其余文件 有什么建议吗 Thanks constructor props super props this state files changedFileI
  • C - sscanf 不忽略空格

    我正在读取文本文件并使用逗号作为分隔符 下面的行确实有效 但是当我打印出 lname 时 它 不会忽略逗号后面的空格并在名称之前打印空格 如何调整代码以忽略空格 文本示例 罗布 史密斯 4 12 岁 某某史蒂夫 琼斯 41 286 某个文本
  • 回形针不支持 .doc 文件

    在 Rails 4 0 2 中 我使用回形针 gem 上传文件 但它不支持 doc 文件 在文件上传字段下方 显示一条错误消息 扩展名与其内容不匹配 在模型中 检查内容类型的验证如下 validates attachment content
  • 比较两个文本文件的最快方法是什么,不将移动的行视为不同

    我有两个文件非常大 每个文件有 50000 行 我需要比较这两个文件并识别更改 然而 问题是如果一条线出现在不同的位置 它不应该显示为不同的 例如 考虑这个文件A txt xxxxx yyyyy zzzzz 文件B txt zzzzz xx
  • 以编程方式在java的resources/source文件夹中创建文件?

    我有两个资源文件夹 src 这是我的 java 文件 资源 这是我的资源文件 图像 properties 组织在文件夹 包 中 有没有办法以编程方式在该资源文件夹中添加另一个 properties 文件 我尝试过这样的事情 public s
  • 从数据库和文件系统中删除文件

    我有一个表引用我们网络上共享位置中的文件 将文件路径存储在数据库中 我有一个按钮需要从数据库中删除记录并从文件系统中删除文件 foreach var report in reports string filePath report Repo
  • 我可以使用 mod_rewrite 更改文件扩展名吗?例如 .jpeg 到 .jpg

    我希望使用 Apache mod rewrite 将文件提供为 jpg 而不是 jpeg 这可能吗 尝试这个 RewriteEngine on RewriteRule jpeg 1 jpg

随机推荐

  • 有趣的网站分享——pornhub风格生成器

    寄语 要说logo设计 xff0c pornhub的logo设计让人印象深刻 xff0c 黑底白字 xff0c 配上一小撮橙色 xff0c 给人极强的冲击力 这不 xff0c 有一个有意思的程序员弄了一个网站 xff0c 专门生成pornh
  • 大小端存储问题

    1 什么是数据的高低位 数据的高位在左 xff0c 低位在右 2 什么是内存的高低位 2 什么是大端存储 小端存储 简单记就是 xff1a 小端 xff1a 低低 xff08 数据低位在内存低位 xff09 大端 xff1a 高低 xff0
  • 【A星算法的优化方案】

    当地图很大的时候 xff0c 或者使用A星算法的寻路频率很高的时候 xff0c 普通的A星算法就会消耗大量的CPU性能急剧下降 xff0c 普通的A星性能还是不过关 接下来我们讲讲A星寻路在遇到性能瓶颈时的优化方案 一 长距离导航 当距离很
  • Java工具类:String与DateTime类型的相互转换

    1 String 转 DateTime 在转换之前需要引入 hutool 依赖 String datestr 61 34 2022 5 19 34 DateTime datetime 61 DateUtil parse datestr 2
  • Iterator迭代器的一般用法

    Iterator迭代器的一般用法 迭代器 xff08 Iterator xff09 迭代器是一种设计模式 xff0c 它是一个对象 xff0c 它可以遍历并选择序列中的对象 xff0c 而开发人员不需要了解该序列的底层结构 迭代器通常被称为
  • socket编程---fgets和fputs函数使用理解

    这一节是继续上一节socket05的讨论 xff0c 来探讨在使用socket进行通信中遇到的一些函数使用理解误区 1 fgets的使用注意点 在写socket通信 xff08 代码见上一篇中 xff0c 只是将sendbuf和recvbu
  • Tarjan算法详细讲解

    Tarjan算法讲解的博客网上找到三篇比较好的 现在都转载了 个人只研究了第一篇 正如博主所说 讲的标比较详细 清晰 剩下两篇也可以看一下 卿学姐视频讲解 https www bilibili com video av7330663 以下内
  • 中文乱码在线恢复网站

    乱码恢复
  • GCC自带的一些builtin内建函数

    title GCC自带的一些builtin内建函数 date 2021 02 27 18 57 00 description 一些GCC自带的内建 bulitin 函数的接口及实现 一 GCC内建函数 最近在刷 leetcode 的时候遇到
  • Shell脚本实用小技巧-教你屏蔽执行命令的所有显示信息,包含错误信息

    前言 xff1a 在Linux中 xff0c 有个 dev null的东西 xff0c 人们一般称之为黑洞 xff0c 大概的意思就是东西就像黑洞一样 xff0c 任何东西丢进去都会消失 xff0c 那么下面就开始进行一些小案例去认识一下这
  • MPU6050应用详解

    MPU6050应用详解 最近项目上要用到 MPU6050 陀螺仪 xff0c 以前没有接触过它 虽然在网上很容易就可以找到了需要的代码 实现了一部分功能 但是却还是对陀螺仪的工作原理不太了解 xff0c 它的代码也需要分析一下 xff0c
  • protobuf详解

    1 protobuf 简介 protobuf protocol buffer 是谷歌内部的混合语言数据标准 通过将结构化的数据进行序列化 串行化 xff0c 用于通讯协议 数据存储等领域和语言无关 平台无关 可扩展的序列化结构数据格式 我们
  • 白泽知识讲堂 | printf漏洞介绍

    引子 Hello各位小伙伴们 xff0c 白泽又和大家见面了 大家还记得自己写的第一个C语言程序吗 xff1f 那是我们和代码爱情的起点 xff0c 一眼万年 没错 xff0c 就是那个耳熟能详的Hello World 1 include
  • Linux生成core文件相关配置,core文件调试示例

    1 生成core文件系统配置 使用ulimit c命令可以查看当前系统对于core文件的配置 xff0c 0表示不生成core文件 xff1b 不为0的数字a表示限制core文件大小不超过a xff0c 单位是k xff1b unlimit
  • Ubuntu 手动配置DNS

    使用ping命令测试百度域名时发现 xff0c 无法解析这个域名 xff0c 说明当前系统上没有配置DNS服务器 配置DNS服务器的方式主要有以下两种 xff1a 目录 1 修改DNS配置文件 etc resolv conf 2 修改网卡配
  • STM32启动文件详解

    启动文件使用的 ARM 汇编指令汇总 启动程序源码注释 点此下载 1 Stack 栈 Stack Size EQU 0x00000400 AREA STACK NOINIT READWRITE ALIGN 61 3 Stack Mem SP
  • Motorola_MSB_LSB

    声明 xff1a 如果涉及侵权 xff0c 请联系本人删除侵权内容 声明 xff1a 本文由本人以以往工作经验为依据 xff0c 总结而得 xff0c 如果错误 xff0c 欢迎指正 xff0c 便于后人参考 xff0c 少走弯路 如果图片
  • 虚拟机怎么安装vmware tools

    这篇文章主要为大家详细介绍了VMware Workstation12安装Ubuntu和VMware Tools教程 具有一定的参考价值 xff0c 感兴趣的小伙伴们可以参考一下 之前我通过百度经验上的过程来安装Ubuntu16 xff0c
  • MySQL数据库改名的三种方法

    MySQL数据库改名的三种方法 前不久去面试 xff0c 被问到Innodb引擎的表如何改数据库名 xff0c 当时我也只回答了MyISAM改如何操作 xff0c 被一些细节问题打败 xff0c 真是操蛋 如果表示MyISAM那么可以直接去
  • C语言详解 FILE文件操作

    1 需要了解的概念 需要理解的知识点包括 xff1a 数据流 缓冲区 文件类型 文件存取方式 1 1 数据流 xff1a 指程序与数据的交互是以流的形式进行的 进行C语言文件的存取时 xff0c 都会先进行 打开文件 操作 xff0c 这个