在Windows平台上,读写磁盘文件是相当多应用程序经常会涉及到的一种功能。该主题涉及到采用C/C++/MFC/Win32(API)中提供的接口函数来操作磁盘文件的方法,以及其中需要注意的地方。
=============================================================
0. 磁盘文件数据存储方式
在介绍各种操作文件方式之前,需要先介绍磁盘上文件数据的组织方式。
实际上,文件是在计算机内存中以二进制表示的数据在外部存储介质上的另一种存放形式。文件通常分为二进制文件和文本文件。二进制文件是包含在ASCII及扩展ASCII字符中编写的数据或程序指令的文件。一般是可执行文件(Exe)、图形、图像、声音等文件。而文本文件(通常也成为ASCII文件),它的每一字节存放的是可表示为一个字符的ASCII代码的文件。这里把文件区分为二进制文件和文本文件,但实际上它们都是以二进制数据的方式来存储的。文本文件里所存储的每一个字节都可以转化为一个可读的字符。譬如’a’,’b’,但在内存中并不会存储'a', 'b',而是存储它们的ASCII码:61和62。
1. C语言对文件操作的支持
在C语言中,对于文件的操作都是利用FILE结构体来进行的。包括文件的打开、文件的读写、文件的关闭、文件指针的定位等。
(1) 文件的打开
文件的打开需要用fopen函数。该函数带2个参数,返回值为指向之前定义的FILE结构体指针。语法定义为
FILE* fopen(const char* filename, const char* mod);
参数1:表示要打开文件的完整路径,例如: “C:\\Test\\Zero_Test.txt”.
参数2:打开文件的方式。取值为下表所示。
文件打开模式
|
意义
|
r/rb
|
为读取而打开。如果文件不存在或不能找到,函数调用失败。
|
w/wb
|
为写入而打开一个空文件。如果给定的文件已经存在,则清空其内容。
|
a/ab
|
为写入而打开一个文件。如果文件存在,则在文件尾部添加新数据,在写新数据之前不会移除原有的EOF标志。如果文件不存在,则新建一个空文件以待写入。
|
r+/rb+
|
打开文件用于写入操作和读取操作,文件必须存在。
|
w+/wb+
|
为写入操作和读取操作打开一个空文件。如果文件已经存在,则清空其内容。
|
a+/ab+
|
打开文件用于读取操作和添加操作。并且添加操作在添加新数据之前会移除该文件中已有的EOF标志,然后当写入操作完成之后再恢复EOF标志。如果指定文件不存在,那么首先将新建一个文件。
|
在上表中,没有带b的模式表示打开的是文本文件,而带b的模式表示打开的是二进制文件。
通常在定义结构FILE时会将其初始化为NULL。在打开文件将函数fopen的返回值赋值给它。之后需要判断文件是否成功打开,可采用如下方式:
if ((pFile = fopen(“C:\\Test\\Zero_Test.txt”, “w”) == NULL)
Print(“Opening File Error.”); // FILE* pFile = NULL;
else
正常写入数据到文件…
(2)文件的关闭
在使用完一个文件之后应该关闭它,以防止它再被误用。“关闭”就是使文件指针变量不再指向该文件,使其脱钩。函数使用方式:
fclose(pFile);
需要注意的是fclose的参数必须是有效的文件指针变量,否则运行时会挂掉。
应该养成在文件数据操作完成后关闭文件的习惯,如果不关闭文件将会丢失数据。同时,在向文件写数据时,是现将数据输出到缓冲区,待缓冲区充满后才正式输出给文件。如果程序运行结束而缓冲区并未充满,则缓冲区中的数据将会丢失。因此利用函数fclose来关闭文件可以避免这个问题。
当然,还有另外一个函数fflush,也可以用来将缓冲区里的数据输出到文件中。函数调用方式:
fflush(pFile);
(3)文件的读写
当涉及到大量数据的读写时,可以采用函数fread和fwrite。这两个函数通常用于二进制文件的读写。函数调用方式如下:
fread(buffer, size, count, fp);
fwrite(buffer, size, count, fp);
buffer是一个指针,是用来存放数据的变量指针,例如内置类型变量的指针,结构体变量指针等。
size是要读写的字节数。特别要注意的是,此处并不是数组的大小,结构体内变量的个数等。最好采用sizeof操作符来求得buffer的内存字节数。
count是size大小的重复次数。
fp是文件指针。
对于这样的结构体:
typedef struct {
int clr_sel; // color mode的选择
int fixval_sel; // fixed value的选择
float thres_val; // threshold value的确定
float thres_scrlbar_pos; // threshold scroll bar位置的确定
int method_sel; // analysis method的选择
int usediff_sel; // use difference of MSA/TSE方式的选择
int usescat_sel; // use MSA/TSE of scatter signal 方式的选择
int remxtalk_sel; // remove crosstalk 方式的选择
float timewin_scrlbar_pos; // time window scroll bar位置的确定
int timewin_sel; // time window模式的选择
int freq_sel; // frequency selection模式的选择
int path_sel; // path selection模式的选择
} IMG_SETTINGS;
IMG_SETTINGS m_img_settings;
文件读写操作时,可采用如下方式:
fwrite(&m_img_settings, sizeof(m_img_settings), 1, pwFile);
fread(&m_img_settings, sizeof(m_img_settings), 1, prFile);
====================================================
如果想读写特定格式的文件,可采用fprintf和fscanf函数。这两个函数通常是针对文本文件进行操作。
函数调用方式如下:
fprintf(pFile, “%d…”, i, j, k …);
fscanf(pFile, “%d…”, i j, k…);
格式化时可以规定读写数据的精度,类型,以及数据之间的分割符等。
例如:
fprintf(pFile, " %d %d %d %d %d %d %d %d \n", sigSize, samp_points, samp_rate,40, avrag_num, 0, 0, 0);
fprintf(pFile, "%d %.2f %s %d %d %d %d \n", vpathdef[i].frequency1/1000,
vpathdef[i].amplitude, sig_type.c_str(), psnset->sensorArray[vpathdef[i].actuator-1].channel-tol,
psnset->sensorArray[vpathdef[i].sensor-1].channel-tol, vpathdef[i].gain, 30);
特别需要注意的是,如果写入的数据的类型相同时,不可为了简便,将格式化的字符串写成如此形式(.., ”%d”,i,j,k…); // i,j,k…同整型类型。
如果这样操作的话,读写的数据便只有数据i了。
最后针对一个面试题来对C语言操作文件的方式作一个总结.
面试题:给你一个整数,例如12345,将这个整数保存到文件中,要求在以记事本打开该文件时,显示的是:12345。
给出三种代码:
(1) 代码1
FILE* pwFile = NULL;
pwFile = fopen(“c:\\Test.txt”, “w”); // create and open file with text mode.
int i = 12345; // However, write number with binary mode.
fwrite(&i, 4, 1, pwFile); // sizeof(int) = 4.
fclose(fwFile);
========================
(2) 代码2
FILE* pwFile = NULL;
pwFile = fopen(“c:\\Test.txt”, “w”);
char ch[5] = {1+48, 2+48, 3+48, 4+48, 5+48 };
fwrite(ch, 1, 5, pwFile); // sizeof(char) = 1, 5*sizeof(char) = 5
fclose(pwFile);
=======================
(3) 代码3
FILE* pwFile = NULL;
pwFile = fopen(“c:\\Test.txt”, “w”);
int i = 12345;
char ch[5];
itoa(i, ch, 10); // transform int number to string
fwrite(ch, 1, 5, fwFile);
fclose(pFile);
==============================
(4) 代码4
FILE* pwFile = NULL;
pwFile = fopen(“c:\\Test.txt”, “w”);
int i = 12345;
fprintf(pwFile, “%d”, i); // write number with specified format.
fclose(pwFile);
==============================
将4种代码在vc中进行编译运行,可以发现只有方式(1)不满足题目要求。
to be continued...