C语言——文件操作(实现带空格字符串任意读写)

本文主要是记录自己在实现带有空格字符串任意读写时所遇到的问题与解决方法。字符串形式为“G1 X500 Y600 F1200”,这是Cura软件生成的打印程序代码格式。

我们先了解一下文件操作都有那些函数:

文件的读写操作:

fgetc ()从文件中读取一个字符 

函数原型:int fgetc(FILE *fp); 
功能说明 :从fp所指文件中读取一个字符。 
参数说明 :fp文件指针,它指向要读取字符的文件。 
返回值 :正常返回: 返回读取字符的代码。 
    非正常返回:返回EOF。例如,要从”写打开”文件中读取一个字符时,会发生错误而返回一个EOF。

fputc() 写一个字符到文件中去 

函数原型:int fputc(char ch,FILE *fp) 
功能说明 :把ch中的字符写入由fp指向的文件中去。 
参数说明 :ch:是一个字符型变量,内存要写到文件中的字符。 
              fp:这是个文件指针,指出要在其中写入字符的文件。 
返回值 :正常返回: 要写入字符。 
          非正常返回:返回EOF。例如,要往”读打开”文件中写一个字符时,会发生错误而返回一个EOF。

fgets() 从文件中读取一个字符串

函数原型 :char *fgets(char *str,int n,FILE *fp) 
功能说明 :从由fp指向的文件中读取n-1个字符,并把它们存放到由str指出的字符数组中去,最后加上一个字符串结束符’\0’。 
参数说明 :str:接收字符串的内存地址,可以是数组名,也可以是指针。 
                n: 指出要读取字符的个数。 
               fp:这是个文件指针,指出要从中读取字符的文件。 
返回值 :正常返回:返回字符串的内存首地址,即str的值。 
               非正常返回:返回一个NULL值,此时应当用feof()或ferror()函数来判别是读取到了文件尾,还是发生了错误。例如,要                 从”写打开”文件中读取字符串,将 发生错误而返回一个NULL值。 

fputs() 写一个字符串到文件中去 

函数原型:int fputs(char *str,FILE *fp) 
功能说明 :把由str指向的字符串写入到fp所指的文件中去。 
参数说明 :str:指出要写到文件中去的字符串。 
               fp:这是个文件指针,指出字符串要写入其中的文件。 
返回值 :正常返回: 写入文件的字符个数,即字符串的长度。 
          非正常返回:返回一个NULL值,此时应当用feof()或ferror()函数来判别是读取到了文件尾,还是发生了错误。例如,要                 往一个”读打开” 文件中写字符串时,会发生错误而返回一个NULL值。

fprintf ()往文件中写格式化数据 

函数原型:int fprintf(FILE *fp,char *format,arg_list) 
功能说明 :将变量表列(arg_list)中的数据,按照format指出的格式,写入由fp指定的文件。fprintf()函数与printf()函数的功能相                      同,只是printf()函数是将数据写入屏幕文件(stdout)。 
参数说明 :fp:这是个文件指针,指向要将数据写入的文件。 
              format:这是个指向字符串的字符指针,字符串中含有要写入数据的格式,所以该字符串成为格式串。格式串描述的                     规则与printf()函数中的格式串相同。 
                   arg_list:是要写入文件的变量表列,各变量之间用逗号分隔。           

fscanf() 格式化读取文件中数据 

函数原型:int fscanf(FILE *fp,char *format,arg_list)

功能说明:将变量表列(arg_list)中的数据,按照format指出的格式,从fp指定的文件读出。

参数说明:fp:这是个文件指针,指向要将数据写入的文件。 

                  format:这是个指向字符串的字符指针,字符串中含有要读出数据的格式,所以该字符串成为格式串。格式串描述的                     规则与scanf()函数中的格式串相同。             

fread() 以二进制形式读取文件中的数据 

函数原型:int fread(void *buffer,unsigned sife,unsigned count,FILE *fp) 
功能说明 :从由fp指定的文件中,按二进制形式将sife*count个数据读到由buffer指出的数据区中。 
参数说明 :buffer:这是一个void型指针,指出要将读入数据存放在其中的存储区首地址。 
                    sife:指出一个数据块的字节数,即一个数据块的大小尺寸。 
                 count:指出一次读入多少个数据块(sife)。 
                       fp:这是个文件指针,指出要从其中读出数据的文件。 
返回值 :正常返回:实际读取数据块的个数,即count。 
        异常返回:如果文件中剩下的数据块个数少于参数中count指出的个数,或者发生了错误,返回0值。此时可以用feof()和               ferror()来判定到底出现了什么 情况。           

fwrite() 以二进制形式写数据到文件中去 

函数原型:int fwrite(void *buffer,unsigned sife,unsigned count,FILE *fp) 
功能说明 :按二进制形式,将由buffer指定的数据缓冲区内的sife*count个数据写入由fp指定的文件中去。 
参数说明: buffer:这是一个void型指针,指出要将其中数据输出到文件的缓冲区首地址。 
                    sife:指出一个数据块的字节数,即一个数据块的大小尺寸。 
                 count:一次输出多少个数据块(sife)。 
                       fp:这是个文件指针,指出要从其中读出数据的文件。 
返回值 :正常返回:实际输出数据块的个数,即count。 
        异常返回:返回0值,表示输出结束或发生了错误。

以上是一些文件操作读写会用到的函数。

那么要想实现文件的随机读写,是要知道文件指针的位置和如何定位指针,下面介绍相关函数:

了解文件指针的当前位置 
函数原型:long ftell(FILE *fp) 
功能说明 :取得由fp指定文件的当前读/写位置,该位置值用相对于文件开头的位移量来表示。 
参数说明 :fp:文件指针。 
返回值 :正常返回:位移量(这是个长整数)。 异常返回:-1,表示出错。

反绕 (非常重要的函数)
函数原型:void rewind(FILE *fp) 
功能说明 :使由文件指针fp指定的文件的位置指针重新指向文件的开头位置。 
参数说明 :fp:文件指针。 
返回值 :无。

随机定位 
函数原型:int fseek(FILE *fp,long offset,int base) 
功能说明 :使文件指针fp移到基于base的相对位置offset处。 
参数说明 :fp:文件指针。 
           offset:相对base的字节位移量。这是个长整数,用以支持大于64KB的文件。 
           base:文件位置指针移动的基准位置,是计算文件位置指针位移的基点。ANSI C定义了base的可能取值,以及这些                     取值的符号常量。base可以取以下三个常量值之一:
                 SEEK_SET(也可直接用数字0表示):此时文件位置指针从文件的开始位置进行移动;
                 SEEK_CUP(对应值为1: 此时文件位置指针从文件的当前位置进行移动;
                 SEEK_END(对应值为2: 此时文件位置指针从文件的结束位置进行移动。
 
返回值 :正常返回:当前指针位置。 异常返回:-1,表示定位操作出错。

还有其他的函数就不再一一介绍了,下面我们来看看实现开头所说的功能要注意的地方,和我遇到的问题。

先直接贴代码。

//C语言中scanf()函数提供的“%[]”格式串可以用来进行多个字符的输入,并对结束符进行自定义。 
//对于%[]还可以用^+任意字符(包括 eof)来结束字符串的输入,如%[^EOF]就是直到有EOF 输入,字符串才中止。
//scanf("%[^\n]", buf);//直到输入回车键,读取才结束
#include
#include
#include
#define BUFSIZE 30

int main()
{
	FILE *fp=NULL;
	char buf[BUFSIZE];
	char ch,str;
	int i;
	int r = 0;//记录行数
	do
	{
		//打开文件
		fp = fopen("F:\\test.txt", "a+");//读写打开一个文本文件,允许读,或在文件末尾追加数据
		if (fp == NULL) {
			printf("文件打开失败!");
		}
		ch = fgetc(fp);//判断文件是否为空
		if (ch == EOF) {
			printf("文件为空!\n");
			printf("请输入要存储的字符串(以#字符结束):\n");
            //写入字符串
			str = getchar();//接收从键盘输入的第一个字符串
			while (str != '#') {
				fputc(str, fp);         //写入到文件
				str = getchar();        //再次接收从键盘输入的字符串
			}
			printf("文件已保存!\n");
			//读取
			rewind(fp);//将指针重置到第一行
			while (!feof(fp)) {//检测文件一共多少行
				ch = fgetc(fp);
				if (ch == '\n') {
					r++;
				}
			}
			getchar();//用来消化最后输入的回车符
			rewind(fp);//将指针重置到第一行
			for (i = 0; i < r; i++) {
				fgets(buf, BUFSIZE, fp);
				/*fscanf(fp, "%[^\n]", buf);*/
				printf("%s", buf);
			}
		}
		else
		{
			printf("文件存在内容!\n");
			printf("选择读取R,写入W,退出Q:");
			str = getchar();
			getchar();//用来消化最后输入的回车符
			if (str == 'R') {
				//读取
				while (!feof(fp)) {//检测文件一共多少行
					ch = fgetc(fp);
					if (ch == '\n') {
						r++;
					}
				}
				rewind(fp);//将指针重置到第一行
				for (i = 0; i < r; i++) {
					fgets(buf, BUFSIZE, fp);
					/*fscanf(fp, "%[^\n]", buf);*/
					printf("%s", buf);
				}
			}
			if (str == 'W') {
				//写入 
				printf("请输入要存储的字符串(以#字符结束输入,Q退出):\n");
				fseek(fp, BUFSIZE, SEEK_END);
				str = getchar();
				while (str != '#') {
					fputc(str, fp);
					str = getchar();
				}
				getchar();//用来消化最后输入的回车符
				printf("文件已保存!\n");
				//读取
				rewind(fp);//将指针重置到第一行
				printf("读取到的文件内容为:\n");
				while (!feof(fp)) {  //检测文件一共多少行
					ch = fgetc(fp);
					if (ch == '\n') {
						r++;
					}
				}
				rewind(fp);//将指针重置到第一行
				for (i = 0; i < r; i++) {
					fgets(buf, BUFSIZE, fp);
					printf("%s", buf);//读取不到刚刚存入的一行
				}
			}
		}
	} while (str!='Q');
	//关闭文件
	fclose(fp);
	exit(0);
	return 0;
}

大家可以发现,我在输入的时候时使用的getchar()函数,其实实现输入“G1 X600 Y500 F1200”这种格式的字符串有很多种方法,大家可以自己多尝试尝试,根据上面介绍的函数,自己动手操作一下,写程序对于新手来说,不可避免会遇到很多问题,需要多多调试,在此不再一一例举。小编也是一个新手,有问题可以一起讨论。

这两句是对实现文件非常重要的两个函数语句,大家可以自己尝试一下如果没有这两条语句会出现什么结果 。

欢迎大家提出问题,有错误可以指出,我会及时纠正。

你可能感兴趣的:(c\c++)