精华内容
下载资源
问答
  • C语言文本文件实现局部修改

    万次阅读 多人点赞 2018-06-17 13:23:59
    前言:以往进行文件操作时,都是以链表(变量)作为用户所见数据与文件数据之间的桥梁。用户改变数据时,先改变链表(变量)中的数据,然后直接将...下面介绍一下文本文件局部修改(覆盖写入)。当然,不进行覆盖...

    前言:以往进行文件操作时,都是以链表(变量)作为用户所见数据与文件数据之间的桥梁。用户改变数据时,先改变链表(变量)中的数据,然后直接将整个链表重新写入文件,以做到“实时同步”,非正常退出程序一般数据也不会丢失。但是数据量很大时,微小的改动就要重写整个文件,浪费很多计算资源。但是在控制台程序中,没有C语言做不到的事,只有C语言不擅长的事。下面介绍一下文本文件的局部修改(覆盖写入)。当然,不进行覆盖的话即实现了插入


    先来回顾一下二进制文件(任意读写文件、随机读写文件)的局部修改
    下面这段程序向man.dat文件中写入三个人的名字,年龄

    typedef struct {
    	char name[20];
    	int age;
    } Data;
    
    int main(){
    	Data man[3];
    	for(int i = 0;i<3;i++){
    		printf("please input %c's name:",i+'A');
    		scanf("%s",man[i].name);
    		printf("please input %c's age:",i+'A');
    		scanf("%d",&man[i].age);
    	}
    	FILE *fp = fopen("man.dat","wb");
    	fwrite(man,sizeof(Data),3,fp);
    	fclose(fp);
    	return 0;
    }
    

    下面这段程序进行了二进制文件的任意读写

    typedef struct {
    	char name[20];
    	int age;
    } Data;
    
    int main(){
    	FILE *fp;
    	char name[100];
    	printf("请输入想要修改的人的名字:");
    	scanf("%s",name);
    	Data data;
    	fp = fopen("man.dat","r+");
    	while(fread(&data,sizeof(Data),1,fp)==1){
    		if(strcmp(data.name,name)==0){找到修改目标 
    			printf("请输入新的名字:");
    			scanf("%s",name);
    			strcpy(data.name,name);修改变量data的name,同样这里也可以修改age 
    			fseek(fp,-sizeof(Data),SEEK_CUR);指针移至修改目标前 
    			fwrite(&data,sizeof(Data),1,fp);写入新的data覆盖原data 
    			printf("修改成功\n"); 
    			break;
    		}
    	}
    	fclose(fp); 
    	
    	puts("开始读取"); 
    	Data test;
    	fp = fopen("man.dat","r+");
    	while(fread(&test,sizeof(Data),1,fp)==1)
    		printf("%s %d\n",test.name,test.age);
    	return 0;
    } 
    

    文本文件局部修改示例程序在文章末尾

    前提条件

    • 待修改数据的数据长度最好已知
    • 修改后的数据长度要比原来小或相同,最好相同
    • 具有写入权限,文件打开方式为**r+**等

    比如int类型的status字段表示该数据元素的使用状态,用1表示正在使用,0表示闲置。现在有改变这个状态的需求,那么这就非常符合本文所述的情况

    主要流程

    1.得到待修改的数据在文件中的位置
    2.将文件内部指针定位到该位置
    3.写入新数据到文件

    首先 我们对fscanf等函数的细节需要有一些了解

    • fscanf所读数据间若存在换行符则读取时文件指针会自动跳过换行符,
      而无需在格式化字符串中加上换行符,且换行符占两个字节(私以为是\r\n的缘故,ps:Windows环境下)
    • fscanf与scanf相似,数据间多余个空格(非格式化字符串间的空格)不造成读取影响
    • 文本文件又称ASCLL码文件,顾名思义我们可以计算出某些位置的字节数

    说明:本文所述偏移字节数为ASCLL文件中的字节数,即字符数

    得到待修改的数据在文件中的位置

    假设当前有data.txt内容为

    0 1 2
    3 4 5
    

    现在我们要得到5的位置

    int num;
    FILE *fp = fopen("data.txt","rt+");
    while(fscanf(fp,"%d",&num)!=EOF&&num!=5);
    读取后文件指针指向5的后面
    
    • 方法一

      long ftell( FILE *stream );发生错误返回-1

      利用ftell函数得到当前当前文件内部指针位置(相对文件首偏移字节数)
      long position = ftell(fp);
      position -= 待修改数据长度;  即得到要定位到的位置
      
    • 方法二

      int fgetpos( FILE *stream, fpos_t *position );fgetpos()函数保存给出的文件流(stream)的位置指针到给出的fpos_t类型的位置变量(pos)中.
      (fpos_t在stdio.h中定义,实质上是一种__int64).fgetpos()执行成功时返回0,失败时返回一个非零值

      利用fgetpos获得文件内部指针位置
      fpos_t pos;
      fgetpos(fp,&pos);
      pos -= 待修改数据长度;
      

    如果我们清晰的知道文件的存储结构,比如它存储的是大量相同的数据块(就像二进制文件那样),我们也可以遍历计数,然后计算出偏移字节数


    将文件内部指针定位到该位置

    //经试验,用于读取的文件指针无法用于写入
    通过上述方法得到需要的文件指针位置(偏移字节数)后
    接下来需要定位文件内部指针到该位置
    int fseek( FILE *stream, long offset, int origin );
    或者
    int fsetpos( FILE *stream, const fpos_t *position );

    • feesk
      其中,fseek函数中int origin参数的值应该是下列值其中之一

      名称 说明
      SEEK_SET(0) 从文件的开始处开始
      SEEK_CUR(1) 从当前位置开始
      SEEK_END(2) 从文件的结束处开始

      fessk从orign处开始,向后偏移offset个字节数,offset < 0 即向前移动
      offset 参数为 fgetpos获取到的fpos_t类型的pos也可,只需(long)pos

    • fsetpos
      fsetpos用于将文件内部指针定位到pos,同理pos也可由ftell得到并转换为fpos_t

    示例
    将上述data.txt中的5修改为0

    fseek(fp,position,0);/#0 == SEEK_SET  从文件首开始
    

    特别地你可以不需要用ftell获得偏移字节数

    fseek(fp,-待修改数值长度,SEEK_CUR);	从当前位置开始
    

    或者

    fsetpos(fp,&pos);
    //pos = (fpos_t) position;
    //fset(fp,pos);
    

    写入新的数据到文件

    fprintf照常写入就好,此时会覆盖原数据(注意换行符),但是此时要注意此时文件指针的位置,不要做多余的写入,新数据长度不足要考虑用空格覆盖原数据,由于fscanf格式化字符串的特点,再读入时空格可以忽略。或者根据存储方式与程序数据定义的特点进行适当的写入

    附上一些输入流操作函数
    rewind(FILE *stream);回滚指针到文件流首
    feof(FILE *stream);判断文件流是否到达文件尾,若到达返回一个非零值
    FILE *freopen( const char *fname, const char *mode, FILE *stream );给一个已存在的流再分配一个不同的文件和方式(mode).在调用本函数后,给出的文件流将会用mode(方式)指定的访问模式引用fname(文件名).
    freopen()的返回值是新的文件流,发生错误时返回NULL.
    fflush();

    示例

    下面的程序将三个结构体变量写入man.txt文件

    typedef struct{
    	char name[20];
    	int age;
    }Data; 
    
    int main(){
    	Data man[3];
    	for(int i = 0;i<3;i++){
    		printf("please input %c's name:",i+'A');
    		scanf("%s",man[i].name);
    		printf("please input %c's age:",i+'A');
    		scanf("%d",&man[i].age);
    	}
    	FILE *fp = fopen("man.txt","w");
    	for(int i =0;i<3;i++){
    		fprintf(fp,"%s %d\n",man[i].name,man[i].age);
    	}
    	fclose(fp); 
    	return 0;
    }
    

    运行及输入
    在这里插入图片描述

    创建的文件
    在这里插入图片描述

    现在我们来修改第二行的16这个数据
    修改程序如下

    typedef struct{
    	char name[20];
    	int age;
    }Data; 
    
    int main(){
    	FILE *fp = fopen("man.txt","r+");
    	Data data = {"liupeidong",16};//修改目标 
    	char name[100];
    	int age;
    	while(fscanf(fp,"%s%d",name,&age)!=EOF){
    		if(strcmp(name, data.name) == 0 && age == data.age){找到目标 
    		fseek(fp,-2,SEEK_CUR);回滚指针至16printf("please input new age:");
    		scanf("%d",&age);
    		fprintf(fp,"%d",age);覆盖写入
    		break; 
    		}
    	} 
    	fclose(fp);
    	return 0;
    } 
    

    运行修改程序
    在这里插入图片描述

    我在Dev中打开了man.txt,然后使用程序修改了它,Dev的提醒
    在这里插入图片描述

    修改后的文件
    在这里插入图片描述


    2018/12/21更新

    展开全文
  • 1113.6.3 文件出错标志和文件结束标志置 0 函数 206 13.7 C库文件 208 13.8 本章小结 第1篇 基本知识 第1章 C++的初步知识 *1.1 从C到C++ *1.2 最简单的C++程序 1.3 C++程序的构成和书写形式 1.4 C++...
  • 1113.6.3 文件出错标志和文件结束标志置 0 函数 206 13.7 C库文件 208 13.8 本章小结 第1篇 基本知识 第1章 C++的初步知识 *1.1 从C到C++ *1.2 最简单的C++程序 1.3 C++程序的构成和书写形式 1.4 C++...
  • 你必须知道的495个C语言问题

    千次下载 热门讨论 2015-05-08 11:09:25
    2.4 在C语言中用什么方法实现抽象数据类型最好? *2.5 在C语言中是否有模拟继承等面向对象程序设计特性的好方法? 2.6 为什么声明externf(structx*p);给我报了一个晦涩难懂的警告信息? 2.7 我遇到这样声明...
  • 难道在C语言中一个结构不能包含指向自己的指针吗? o 2.7 怎样建立和理解非常复杂的声明?例如定义一个包含 N 个指向返回指向字符的指针的函数的指针的数组? o 2.8 函数只定义了一次, 调用了一次, 但编译器提示...
  • 《你必须知道的495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    2.4 在C语言中用什么方法实现抽象数据类型最好? 22 *2.5 在C语言中是否有模拟继承等面向对象程序设计特性的好方法? 22 2.6 为什么声明extern f(struct x *p); 给我报了一个晦涩难懂的警告信息? 23 2.7 我...
  • 2.4 在C语言中用什么方法实现抽象数据类型最好? 22 *2.5 在C语言中是否有模拟继承等面向对象程序设计特性的好方法? 22 2.6 为什么声明extern f(struct x *p); 给我报了一个晦涩难懂的警告信息? 23 2.7 我...
  • 你必须知道的495个C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    难道在C语言中一个结构不能包含指向自己的指针吗? . . . . 3 1.7 怎样建立和理解非常复杂的声明?例如定义一个包含N 个指向返 回指向字符的指针的函数的指针的数组? . . . . . . . . . . . . . . 3 1.8 函数只定义...
  • 9.3.2 嵌套类和局部类 168 9.3.3 静态成员函数 169 9.4 静态初始化的依赖因素 171 9.5 转换连接指定 174 9.6 小结 174 9.7 练习 174 第10章 引用和拷贝构造函数 176 10.1 C++中的指针 176 10.2 C++中的引用 176 ...
  • python cookbook(第3版)

    2016-01-06 22:24:38
    5.17 将字节写入文本文件 5.18 将文件描述符包装成文件对象 5.19 创建临时文件和文件夹 5.20 与串行端口的数据通信 5.21 序列化Python对象 第六章:数据编码和处理 6.1 读写CSV数据 6.2 读写JSON数据 6.3 ...
  • 57 理解文本文件和文档文件 58 创建并使用源文件 59 创建并使用头文件 60 使用保护:避免头文件多次被包含 61 理解makefile 62 理解可执行文件 第六章 理解字符 63 理解字符:ASCII码字符 64 理解字符:转换ASCII码...
  • 57 理解文本文件和文档文件 58 创建并使用源文件 59 创建并使用头文件 60 使用保护:避免头文件多次被包含 61 理解makefile 62 理解可执行文件 第六章 理解字符 63 理解字符:ASCII码字符 64 理解字符:转换ASCII码...
  • 57 理解文本文件和文档文件 58 创建并使用源文件 59 创建并使用头文件 60 使用保护:避免头文件多次被包含 61 理解makefile 62 理解可执行文件 第六章 理解字符 63 理解字符:ASCII码字符 64 理解字符:转换ASCII码...
  • 57 理解文本文件和文档文件 58 创建并使用源文件 59 创建并使用头文件 60 使用保护:避免头文件多次被包含 61 理解makefile 62 理解可执行文件 第六章 理解字符 63 理解字符:ASCII码字符 64 理解字符:转换ASCII码...

空空如也

空空如也

1 2 3
收藏数 49
精华内容 19
关键字:

c语言文本文件实现局部修改

c语言 订阅