• 文件操作-


    文件操作

    这里先来 知道一下 操作文件的基本方法

    1.打开文件

    2.读 / 写 - 操作文件

    3.关闭文件。

    在此之前我们先来了解一下什么是文件。

    什么是 文件

    磁盘上的文件是文件。
    但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

    程序文件

    包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境

    后缀为.exe)。

    数据文件

    文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,
    或者输出内容的文件

    在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显
    示器上

    其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件

    有关文件的 输出 与 输入 关系图

    在这里插入图片描述

    文件名

    一个文件要有一个唯一的文件标识,以便用户识别和引用。

    文件名包含3部分:文件路径+文件名主干+文件后缀
    例如: c:\code\test.txt

    为了方便起见,文件标识常被称为文件名。

    文件的打开和关闭

    文件指针

    缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。

    每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名

    字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统

    声明的,取名FILE.

    这里 我们先要 看FILE是如何定义的 ,但是2019 已经封装的 看不到了,这里 那 2013VS来查看

    VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

    struct _iobuf {
        char *_ptr;
        int  _cnt;
        char *_base;
        int  _flag;
        int  _file;
        int  _charbuf;
        int  _bufsiz;
        char *_tmpfname;
       };
    typedef struct _iobuf FILE;  --》 FILE就算 结构体指针,   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,
    使用者不必关心细节。
    一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

    下面我们可以创建一个FILE*的指针变量:

    FILE* pf;//文件指针变量
    
    • 1

    定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。

    通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。

    在这里插入图片描述

    文件的打开和关闭

    文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。

    在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指
    针和文件的关系。

    ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件

    打开文件fopen

    在这里插入图片描述

    这里可以看看文件的访问模式

    在这里插入图片描述

    演示 “w” 写 文件

    在这里插入图片描述

    关闭文件 fclose

    注意使用 fopen 可能 打开文件 失败,返回的 是 NULL ,这里 那"r" 来 演示

    在这里插入图片描述

    知道了 打开 和 关闭文件,那么我们 来了解 一下 文件的 顺序读写

    文件的顺序读写

    先来看一下我们 要了解的 函数

    在这里插入图片描述

    fputc 写一个 字符

    在这里插入图片描述

    这里 字符 是 ASCII 值 所以 这里可以 使用 int 接收
    在这里插入图片描述

    fgetc 读一个 字符

    在这里插入图片描述

    在这里插入图片描述

    这里 读出 可能 返回 EOF 那么 我们是不是 可以 通过 这个,来设置一个循环,来打印 这里 全部的 字符

    在这里插入图片描述

    fputs 写一行 字符

    在这里插入图片描述

    在这里插入图片描述

    注意事项:

    注意:这里 我们 一开始是不是 在test.txt 中 写 入了 a 到 z 这里我们 再次打开文件 写文件的时候就会清空 这个文件 ,重新 添加 新的内容,

    如果需要 将 写 文件的 “w” 改为 “a” 为 追加
    在这里插入图片描述

    fgets 读一行 字符

    在这里插入图片描述

    在这里插入图片描述

    补充:

    这里 打印错误信息 可以 使用 函数 perror

    在这里插入图片描述

    fprintf 格式化输出函数

    在这里插入图片描述

    在这里插入图片描述

    fscanf 格式化输入函数

    在这里插入图片描述

    在这里插入图片描述

    补充: 有关流的补充

    在这里插入图片描述


    FILE*
    文件流

    任何一个 c 程序,只要运行起来就会默认打开3个流

    FILE* stdin --> 标准输入流(键盘)

    FILE* stdout --> 标准输出 流(屏幕)

    FILE* stderr --> 标准错误流 (屏幕)

    使用 fprintf 打印到 屏幕上

    在这里插入图片描述

    fwrite 二进制 输出

    在这里插入图片描述

    fread 二进制 输入

    在这里插入图片描述

    在这里插入图片描述

    到此我们 的 上面的读和写 都完成了,那么接下来我们 来 对比 下 几组函数

    对比一组函数

    scanf/ fscanf/ sscanf

    printf/ fprintf/ sprintf

    在这里插入图片描述

    文件 版本 通讯录

    这里我们 以前的通讯录是不是 只能打开使用,不能保存 数据,那么我们 这里学习了文件操作,那么这里我们就来改进一下我们的 通讯录

    这里我们 只需要在 以前的版本中 添加 写 文件 和 读文件 即可、

    #define _CRT_SECURE_NO_WARNINGS
    
    #include "contact.h"
    
    void menu()
    {
    	printf("*******************************************\n");
    	printf("******    1.add                2.del ******\n");
    	printf("******    3.search             4.modify****\n");
    	printf("******    5.show               6.clear  ****\n");
    	printf("******    7.sortName           0.exit *****\n");
    	printf("*******************************************\n");
    
    }
    
    enum option
    {
    	EXIT,
    	ADD,
    	DEL,
    	SEARCH,
    	MODIFY,
    	SHOW,
    	CLEAR,
    	SORTNAME
    };
    int main()
    {
    	int input = 0;
    	Contact con;
    	InitContact(&con);
    	do
    	{
    		menu();
    		printf("请选择:>");
    		scanf("%d", &input);
    		switch (input)
    		{
    		case ADD:
    			AddContact(&con);
    			break;
    		case DEL:
    			DelContact(&con);
    			break;
    		case SEARCH:
    			SearchContact(&con);
    			break;
    		case MODIFY:
    			ModifyContact(&con);
    			break;
    		case SHOW:
    			ShowContact(&con);
    			break;
    		case CLEAR:
    			ClearContact(&con);
    			break;
    		case SORTNAME:
    			SortContact(&con);
    			break;
    		case EXIT:
    			//保存信息到文件
    			SaveContact(&con);
    			//销毁通讯录
    			DestroyContact(&con);
    			printf("退出通讯录\n");
    			break;
    		default:
    			printf("选择错误\n");
    			break;
    		}
    	} while (input);
    	return 0;
    }
    
    函数声明
    #define _CRT_SECURE_NO_WARNINGS
    
    #include 
    #include 
    #include 
    #include 
    
    
    #define DEFAULT_SZ 3
    #define INC_SZ 2
    #define MAX 1000
    #define MAX_NAME 20
    #define MAX_SEX 10
    #define MAX_TELE 12
    #define MAX_ADDR 30
    typedef struct PeoInfo
    {
    	char name[MAX_NAME];
    	int age;
    	char sex[MAX_SEX];
    	char tele[MAX_TELE];
    	char addr[MAX_ADDR];
    }PeoInfo;
    
    
    //静态版本
    //typedef struct Contact
    //{
    //	PeoInfo data[MAX];
    //	int count;
    //}Contact;
    
    //动态版本
    typedef struct Contact
    {
    	PeoInfo* data;
    	int count;
    	int capacity;
    }Contact;
    
    //初始化
    int InitContact(Contact* pc);
    
    //添加
    void AddContact(Contact* pc);
    
    //打印
    void ShowContact(const Contact* pc);
    
    //删除
    void DelContact(Contact* pc);
    
    //查找
    void SearchContact(Contact* pc);
    
    //修改
    void ModifyContact(Contact* pc);
    
    //清空
    void ClearContact(Contact* pc);
    
    //排序
    void SortContact(Contact* pc);
    
    
    //销毁
    void DestroyContact(Contact* pc);
    
    //保存通讯录信息到文件
    void SaveContact(Contact* pc);
    
    //加载文件内容到通讯录
    void LoadContact(Contact* pc);
    
    //
    void CheckCapacity(Contact* pc);
    
    
    函数实现
    
    #define _CRT_SECURE_NO_WARNINGS
    
    #include "contact.h"
    
    void LoadContact(Contact* pc)
    {
    	FILE* pf = fopen("contact.dat", "r");
    	if (pf == NULL)
    	{
    		perror("LoadContact");
    		return;
    	}
        
    	//读文件
    	PeoInfo tmp = { 0 };
        根据 fread  读二进制 的 返回值来判断,如果这里 读到了 数据 返回 读取数据的个数这里读一个元素那么就返回1
            如果读到末尾 那么 就返回 0 这里是不是 正好就 结束循环了。
    	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
    	{
            
           如果我们 的文件 中的数据 大于我们 的初始开辟的空间,那么我们 是不是 需要扩容, 这里就可以掉用我们的扩容函数来判断
    		//是否需要增容
    		CheckCapacity(pc);
    		pc->data[pc->count] = tmp;
    		pc->count++;
    	}
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    }
    
    int InitContact(Contact* pc)
    {
    	assert(pc);
    	pc->count = 0;
    	pc->data = (PeoInfo*)calloc(3, sizeof(PeoInfo));
    	if (pc->data == NULL)
    	{
    		printf("InitContact:%s\n", strerror(errno));
    		return 1;
    	}
    	pc->capacity = DEFAULT_SZ;
    
    	//加载文件
    	LoadContact(pc);
    
    	return 0;
    }
    
    
    void CheckCapacity(Contact* pc)
    {
    	if (pc->count == pc->capacity)
    	{
    		PeoInfo* ptr = realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
    		if (ptr == NULL)
    		{
    			printf("ADDContact:%s\n", strerror(errno));
    			return;
    		}
    		else
    		{
    			pc->data = ptr;
    			pc->capacity += INC_SZ;
    			printf("增容成功\n");
    		}
    	}
    }
    
    //动态的版本
    void AddContact(Contact* pc)
    {
    	assert(pc);
    	CheckCapacity(pc);
    	printf("请输入名字:");
    	scanf("%s", pc->data[pc->count].name);
    	printf("请输入年龄:");
    	scanf("%d", &pc->data[pc->count].age);
    	printf("请输入性别:");
    	scanf("%s", pc->data[pc->count].sex);
    	printf("请输入电话:");
    	scanf("%s", pc->data[pc->count].tele);
    	printf("请输入地址:");
    	scanf("%s", pc->data[pc->count].addr);
    
    	pc->count++;
    	printf("增加成功\n");
    }
    
    
    
    void ShowContact(const Contact* pc)
    {
    	assert(pc);
    	int i = 0;
    	printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    	for (i = 0; i < pc->count; i++)
    	{
    		printf("%-20s\t%-3d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age,
    			pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);
    	}
    }
    
    static int FindByName(Contact* pc, char name[])
    {
    	assert(pc);
    	int i = 0;
    	for (i = 0; i < pc->count; i++)
    	{
    		if (0 == strcmp(pc->data[i].name, name))
    		{
    			return i;
    		}
    	}
    	return -1;
    }
    
    void DelContact(Contact* pc)
    {
    	char name[MAX_NAME] = { 0 };
    	assert(pc);
    	int i = 0;
    	if (pc->count == 0)
    	{
    		printf("通讯录为空,没有信息可以删除\n");
    		return;
    	}
    	printf("请输入要删除人的名字:>");
    	scanf("%s", name);
    
    	//查找
    	int pos = FindByName(pc, name);
    
    	if (pos == -1)
    	{
    		printf("要删除的人不存在\n");
    		return;
    	}
    	//删除
    	for (i = pos; i < pc->count - 1; i++)
    	{
    		pc->data[i] = pc->data[i + 1];
    	}
    	pc->count--;
    	printf("删除成功\n");
    }
    
    
    void SearchContact(Contact* pc)
    {
    	char name[MAX_NAME] = { 0 };
    	assert(pc);
    	printf("请输入要查找人的名字:>");
    	scanf("%s", name);
    	int pos = FindByName(pc, name);
    	if (pos == -1)
    	{
    		printf("要查找的人不存在\n");
    		return;
    	}
    	else
    	{
    		printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
    		printf("%-20s\t%-3d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name, pc->data[pos].age,
    			pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr);
    	}
    
    }
    
    
    void ModifyContact(Contact* pc)
    {
    	char name[MAX_NAME] = { 0 };
    	assert(pc);
    	printf("请输入要修改人的名字:>");
    	scanf("%s", name);
    	int pos = FindByName(pc, name);
    	if (pos == -1)
    	{
    		printf("要修改的人不存在\n");
    		return;
    	}
    	else
    	{
    		printf("请输入名字:");
    		scanf("%s", pc->data[pos].name);
    		printf("请输入年龄:");
    		scanf("%d", &pc->data[pos].age);
    		printf("请输入性别:");
    		scanf("%s", pc->data[pos].sex);
    		printf("请输入电话:");
    		scanf("%s", pc->data[pos].tele);
    		printf("请输入地址:");
    		scanf("%s", pc->data[pos].addr);
    		printf("修改成功\n");
    	}
    
    }
    
    
    void ClearContact(Contact* pc)
    {
    	assert(pc);
    	pc->count = 0;
    	memset(pc->data, 0, sizeof(pc->data));
    	printf("清空成功!\n");
    
    }
    
    
    
    int cmp_by_name(const void* e1, const void* e2)
    {
    	return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
    }
    void SortContact(Contact* pc)
    {
    	assert(pc);
    	for (int i = 0; i < pc->count - 1; i++)
    	{
    		qsort(pc->data, pc->count, sizeof(pc->data[0]), cmp_by_name);
    	}
    	printf("排序成功!\n");
    }
    
    
    
    void DestroyContact(Contact* pc)
    {
    	assert(pc);
    	free(pc->data);
    	pc->data = NULL;
    
    }
    
    
    写文件
    void SaveContact(Contact* pc)
    {
    	FILE*pf = fopen("Contact.dat", "w");
    	if (pf == NULL)
    	{
    		perror("SaveContact");
    		return;
    	}
    	//写文件
    	int i = 0;
    	for (i = 0; i < pc->count; i++)
    	{
    		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
    	}
    	//关闭文件
    	fclose(pf);
    	pf = NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410

    文件版本的 通讯录 完成了 那么 接下了我们来 看一看 文件的随机读写

    文件的随机读写

    fseek

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    我们 了解了这个函数,是不是有人会有疑问,这里文件指针的 偏移量是如何去求的 呢。

    别急 我们接下来的 ftell 就是用来 求 文件指针相对起始位置的偏移量

    ftell

    返回文件指针相对于起始位置的偏移量

    long int ftell ( FILE * stream );
    
    • 1

    在这里插入图片描述

    这里我们 求到 了 文件指针的偏移量,那么我们的指针,移动到后面,我们能不能让他回到起始位置, 这里就有一个函数 rewind

    然文件指针回到文件的起始位置

    rewind

    让文件指针的位置回到文件的起始位置

    void rewind ( FILE * stream );
    
    • 1

    在这里插入图片描述

    文本文件和二进制文件

    根据数据的组织形式,数据文件被称为文本文件或者二进制文件。

    数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

    如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文
    本文件。

    一个数据在内存中是怎么存储的呢?

    字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。

    如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),

    而二进制形式输出,则在磁盘上只占4个字节

    在这里插入图片描述

    在这里插入图片描述

    文件读取结束的判定

    我们学习文件操作,学到现在是不是 会有一个问题,文件是怎么是读取结束的呢?

    这里我们就 需要学习一下feof 函数,但是feof有很多人 用错了 这里我们来 学习一下

    feof

    牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
    而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。

    1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
      例如:
      fgetc 判断是否为 EOF .
      fgets 判断返回值是否为 NULL .
    2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
      例如:
      fread判断返回值是否小于实际要读的个数。

    在这里插入图片描述

    这里在来看这个,我们 nmemb 这个参数,读取的是你输入 的个数,如果这里返回值为了0 就说明到了末尾

    下面来几个例子

    文本文件的例子:

    #include 
    #include 
    int main(void)
    {
      int c; // 注意:int,非char,要求处理EOF
      FILE* fp = fopen("test.txt", "r");
        fp == NULL   !NULL 就 能 进入 if 语句
      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);
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    二进制文件的例子:

    #include 
    enum { SIZE = 5 };
    int main(void)
    {  
      double a[SIZE] = {1.,2.,3.,4.,5.};
        
      FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
        
      fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
        
      fclose(fp);
        
      double b[SIZE];
        
      fp = fopen("test.bin","rb");
        
      size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
        
      if(ret_code == SIZE) {
          
        puts("Array read successfully, contents: ");
          
        for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
          
        putchar('\n');
          
     } else { // error handling
          
       if (feof(fp))
           
         printf("Error reading test.bin: unexpected end of file\n");
          
       else if (ferror(fp)) {
           
         perror("Error reading test.bin");
           
       }
     }
      fclose(fp);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    文件缓冲区

    ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序
    中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装
    满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓
    冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根
    据C编译系统决定的

    在这里插入图片描述

    #include 
    #include 
    int main()
    {
        FILE*pf = fopen("test.txt", "w");
        
        fputs("abcdef", pf);//先将代码放在输出缓冲区
        
        printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
        
    	Sleep(10000);
        
    	printf("刷新缓冲区\n");
        
    	fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
        
        //注:fflush 在高版本的VS上不能使用了
        printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
        
        Sleep(10000);
        
        fclose(pf);
        
        //注:fclose在关闭文件的时候,也会刷新缓冲区
        pf = NULL;
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    这里可以得出一个结论:
    因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文
    件。
    如果不做,可能导致读写文件的问题

    到此文件操作就结束了。
    最后
    最后嘿嘿

  • 相关阅读:
    基于C#实现的《勇士返乡》游戏设计
    GUI编程--PyQt5--QDiaglog
    CNI设计解读
    pytorch中tensor转成图片保存
    前端学习案例-有哪些是你成为一名开发之后才知道的事情2021
    浅谈JWT(Json Web Token)
    接口与抽象类的区别
    SpringMVC如何转发及重定向(forward、redirect)
    计算机网络复习总结5
    图数据库Neo4j的调研
  • 原文地址:https://blog.csdn.net/mu_tong_/article/details/125870859