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。如果没有指定文件路径,则默认为当前工作目录。如:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->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. 打开文件并进行判断和关闭文件
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->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()函数检查文件是否读取完毕
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#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)
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#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
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#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 (不正确的重构)
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#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()函数的使用
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#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函数的使用
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#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函数的使用
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#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);
分享到:
相关推荐
【知识点详解】 1. **C语言基础**:C语言是程序设计的基础,涉及到变量、数据类型、控制结构(如if语句、for循环、while循环)、函数、指针等概念。在游戏开发中,这些基本元素用于构建游戏逻辑和数据结构。 2. **...
"C语言学习-排序详解完整" 本资源摘要信息将详细介绍C语言学习中排序的概念、类型、算法和实现细节。 排序的概念 排序是将任一文件中的记录,通过某种方式整理成按关键字递增(或递减)次序布列的操作环节。假定...
【C语言进阶知识点详解】 C语言是一种强大的、低级的编程语言,是许多现代编程语言的基础。在进阶学习中,通常会涵盖以下主题: 1. **指针操作**:C语言的精髓之一,指针能够直接操作内存,理解指针的用法对于优化...
《C语言实现的航班订票系统详解》 在IT领域,C语言因其高效、灵活的特点,常被用于开发系统级软件和嵌入式系统。本篇文章将深入探讨一个基于C语言编写的航班订票系统,这是一个典型的命令行界面程序,旨在帮助用户...
**Newmark-β法详解** Newmark-β法是基于半隐式方法的时间积分技术,由Newmark于1959年提出。它的基本思想是将结构的动力方程转化为一组代数方程,并在每个时间步长内求解这些方程。这种方法的核心在于选择合适的...
《C语言图书管理系统源码详解》 在编程领域,C语言以其高效、灵活和底层特性深受程序员喜爱。本文将深入探讨一个基于C语言编写的图书管理系统源码,旨在帮助读者理解C语言在实际项目中的应用,提升编程技能。 图书...
### C语言基础知识与核心概念详解 #### C语言概述与源程序结构特点 - **源程序组成**:一个C语言源程序可能由一个或多个源文件组成。这些源文件中的每一个都可以包含一个或多个函数。 - **主函数的重要性**:一个...
### C语言教程知识点详解 #### 一、C语言概述 **1.1 C语言的发展过程** C语言由Dennis Ritchie于1972年在贝尔实验室开发完成,最初是为了移植Unix操作系统而设计的。随着时间的推移,C语言逐渐成为一种广泛应用的...
#### 四、代码实现详解 1. **核心数据结构定义** ```c typedef struct {/* 学生信息结构体 */ char num[20]; /* 学号 */ char name[20]; /* 姓名 */ char unit[20]; /* 单位/班级 */ char phone[13]; /* ...
#### 四、C语言编程技巧详解 1. **软件架构**: - 模块划分是软件架构设计的关键。 - 模块化设计能够提高代码的可读性和可维护性。 - 模块通常由一个`.c`文件和一个`.h`文件组成,其中`.c`文件包含了具体的实现...
《C语言实现的酒店管理系统详解》 在信息技术领域,C语言以其高效、灵活和底层控制的优势,被广泛应用于系统开发,尤其是嵌入式系统和小型应用程序。本篇将深入探讨一个使用C语言编写的酒店管理系统的实现细节,该...
一般地,在C语言或C++中,会把用来#include的文件的扩展名叫.h,称其为头文件。#include文件的目的就是把多个编译单元(也就是c或者cpp文件)公用的内容,单独放在一个文件里减少整体代码尺寸;或者提供跨工程公共...
**C语言Wint-Tc工具详解** C语言作为一门基础且强大的编程语言,深受程序员喜爱。在Windows操作系统中,为了方便C程序的编写、编译和调试,开发了许多集成开发环境(IDE)和编辑器。其中,Win-TC就是一款专门为...
而连接器则负责将编译后的对象文件链接成最终的可执行文件。此外,它还支持调试功能,帮助开发者查找并修复程序中的错误。 2. **命令行操作**:Win-TC保留了DOS命令行操作方式,这对于理解早期计算机工作原理和熟悉...
《C语言与Linux系统工具库util-linux 2.39.1详解》 在计算机科学领域,C语言作为一门基础且强大的编程语言,被广泛应用于系统级开发和各种软件构建。而在Linux操作系统中,util-linux库是不可或缺的一部分,它包含...
**C语言编程——迷宫系统详解** C语言是一种强大的、底层的编程语言,它以其高效、灵活和可移植性在编程领域占据着重要的位置。在这个“C语言编程-迷宫”项目中,开发者使用C语言构建了一个迷宫系统,旨在展示如何...
《单片机C语言实例——AT24C02存储技术详解》 在电子工程领域,单片机(Microcontroller Unit, MCU)是核心的控制部件,而C语言作为广泛应用的编程语言,使得硬件控制更加方便高效。本实例将深入探讨如何使用C语言...
《C语言实现的学籍管理系统详解》 C语言是一种基础且强大的编程语言,它以其简洁的语法和高效性被广泛应用于各种系统开发中。在本项目中,“C语言课设-学籍管理系统”是一个典型的软件工程实践,它涵盖了数据结构、...