前言(可跳过)

在进行大型文件的读写操作时,若采用读打开文件a,再将“a中修改删除位置之前的内容+修改删除的内容+a中修改删除位置之后的内容”保存到文件b,关闭并删除文件a,将文件b改名为与文件a同名的简单办法,即使结果同修改指定位置的数据的方式相同,但程序所占时间片和内存空间都会难以想象的巨大。

作为一个优秀的程序员,这种掩耳盗铃的办法根本不是应该采取的办法,采用追加写入然后替换源文件的方式根本不能代替对指定位置局部修改的功能,我们必须直面问题,怎么将数据写入指定位置,这不是PTA黑盒测试,不能只关注结果。纵使结果相同,但只要实现方式不正确,问题就还没解决。

然而,我查看许多平台上许多相似提问的回答,大多人都采用一些代替方法来解决问题,这并不值得苛责,闻道有先后,术业有专攻,每个程序员都有他们自己不会的内容,这很正常,甚至我的水平比看这篇文章的大多数人都要来得差。但问题是,知之为知之,不知为不知,不会就是不会,不会就不要自负地觉得自己的办法是唯一的办法。有的人只会那些代替办法,还信誓旦旦说没有更好的办法了,我之前差点就以为只有这些替代办法了,没有办法直接对指定文件进行修改。承认自己能力不足很难吗,可能对某些人来说很难,但是不管怎么说,自己能力不足不愿听取他人意见还自负地去误人子弟是不对的。

当然,我也能力也远远不足,以下我所采用的办法也不是最好的办法,就权当我抱砖引玉,希望我的方法能对各位读者有所启发。

具体需求

不同的人有不同的需求,我是在处理二进制文件时所产生的需求,我要求对该二进制文件的制定位置进行读写操作,且要求在未找到该文件的情况下新建文件。

我在查找解决问题的方法中,看到有些人的需求是在文本文件中查找指定数据并修改,在此也一并解决。

解决思路

有些东西解决起来感觉很难,但一旦看到解决办法,啊,就感觉真的好简单。

就像那经典的程序员语句:“卧槽,程序还能这么写!”

这里的思路实现起来其实很简单,但是为什么我当初想了那么久才想到呢T_T

我们要注意到,在C语言标准I/O(输入与输出)库中,fopen()函数的模式字符串如下:

我们发现w写入会清空原文件,a写入只能追加,而+号代表可以读和写,所以其实我们只要采用r+型就可以做到对指定位置的输入了。(看来语文真的很重要)

注意,一定要是r+型(含rb+,rt+)任何其他方式都不行

事实上,ANSI C标准库一直提供更新文件的方式,不过我一直没注意到r+方式也可以写入,并且还是可以在文件中修改删除的那种方式,真的是踏破铁皮无觅处,得来全不费工夫。

不过我的需求还差一点,那就是文件不存在还需新建一个,对此我采用了初始化检查中插入a+的方式。

解决代码

注意:在VS2019环境下的部分实现代码

#include//由于iostream包含stdio.h,体积过于庞大,故不采用

bool Examination() {//检查函数

FILE* test;//设置文件指针

errno_t open_return;//文件打开返回值,若返回非0则失败

open_return = fopen_s(&test, "data", "ab+");//以二进制打开程序目录下的data文件,若无则新建

fclose(test);//检索成功,关闭文件

return (bool)open_return;//检查正常

}

int main() {

char Exam_Return = Examination();//检查data文件

if (Exam_Return) {}//返回1则检查失败

FILE* data;//设置文件指针

errno_t open_return;//文件打开返回值,若返回非0则失败

open_return = fopen_s(&data, "data", "rb+");//以读写二进制打开程序目录下已存在的data文件

Exam_Return = fclose(data);//成功关闭返回0

if (Exam_Return) {}//文件关闭失败

return 0;

}

注意,VS中的文件函数同其他编译器不同,非VS环境下:

#include//由于iostream包含stdio.h,体积过于庞大,故不采用

bool Examination() {//检查函数

FILE *test;//设置文件指针

test = fopen("data", "ab+");//以二进制打开程序目录下的data文件,若无则新建

fclose(test);//检索成功,关闭文件

return 0;

}

int main() {

char Exam_Return = Examination();//检查data文件

if (Exam_Return) {}//返回1则检查失败

FILE *data;//设置文件指针

data = fopen("data", "rb+");//以读写二进制打开程序目录下已存在的data文件

Exam_Return = fclose(data);//成功关闭返回0

if (Exam_Return) {}//文件关闭失败

return 0;

}

以上只是初始化的代码,不包含输入输出功能,各位读者可以根据自己的需要在此基础上进行相应的增减。

比如我所写入文件的数据为结构体(类),以下是部分输入代码(VS2019环境下):

//结构体指针为Present,size为结构体大小

function_return=fseek(data, (Present->num - 1) * size, SEEK_SET); //指针移至修改目标前

if (function_return != 0) {//fseek返回非0表明错误

rewind(data);//重置文件指针

return 1;

}

function_return = fwrite(Present, size, 1, data);//注意:在a+方式下fwrite函数从文件末尾开始写入,而在上述的r+方式下,fwrite可以在文件中写入

rewind(data);

if (!function_return) { printf("写入失败\n"); return 1; }//失败返回0值

printf("写入成功\n");

return 0;

以下是部分输出代码:

bool Load(FILE* u, struct person* n, int x) {//根据编号查找并加载文件指定结构体,若失败则返回1

rewind(u);

int function_return = 0;

if (x < 1) { printf("输入无效\n"); return 1; }//若n小于1,返回0,当n=1时,查找编号为1的结构体,即第0(n-1)个

function_return = fseek(u, (x - 1) * size, SEEK_SET);//成功返回0值

if (function_return) { printf("查找失败\n"); return 1; }//失败返回非0值

printf("查找成功\n");

function_return = fread(n, size, 1, u);//成功返回非0值

if (!function_return) { printf("读取失败\n"); return 1; }//失败返回0值

printf("读取成功\n");

Output_Structure(n);

rewind(u);

return 0;

}

bool Output_Structure(struct person* n) {//结构体输出函数

printf("\n--------------------\n");

printf("编号:%d\n", n->num);

printf("姓名:%s\n", n->name);

printf("情况说明:%s\n", n->circumstance);

printf("相似人物姓名:%s\n", n->related_name);

printf("相似人物编号:%d\n", n->related_number);

printf("相似原因:%s\n", n->reason);

printf("人物评价:%s\n", n->comment);

printf("--------------------\n");

return 0;

}

实验结果

经实验,上述代码可以实现在文件中间插入

实验结果:

查找1的结果:

查找2的结果:

修改1的结果:

再次查找1的结果:

再次查找2的结果:

可以看到,1被修改了,而2没有发生变动。

如此,便通过C语言实现了对文件指定位置数据的修改。

接下来,再尝试对文件的追加写入:

查找10的结果:

写入10的结果:

再次查找10的结果:

对文件的追加写入成功实现。

可以看到,在fopen()函数中采用r+方式打开文件,既可以在文件中修改数据,也可以追加写入,十分方便。

反思与总结(可跳过)

怎么说呢,我承认我可能有点思维僵化了。

一直以来,我始终认为只有w和a格式的fopen()函数才可以输入,但是显然,r+格式也可以输入,而且是可以在文件中输入的那种。

真没想到,读的扩展是可以输入的,想必那些知道这点的人也根本不会去回答那些如何用C语言在文件的指定位置输入的问题吧,因为这可以算是基本功的一部分了。

这件事情给我的带来的教训就是不能忽视那些看起来根本无关的功能,也许那些函数或者功能就能解决我当下面临的最大难题呢,谁也未可知,不是吗?

最后,希望这篇文章能够对各位读者有一点启发。如果这篇文章可以帮助你们解决一些问题,那我就十分满意了。

如果还有读者对相应功能的实现还存在一些疑惑,或者文章还存有阐述不甚清楚的地方,欢迎大家在文章下方留言指点,我会在方便的时候回复的。

其他需求的实现

查找文本文件中特定文本并进行替换的部分实现代码(非VS环境下):

#include//加载字符串比较函数

//fp为文件指针,size为结构体数据长度

while(fread(Present,size,1,fp)==1){//每次读入一个结构体长度的数据,返回1则代表读取成功

if(strcmp(Present->name,"Test")==0){//如果Present所指向的结构体名字与文件中字符串配对成功

fseek(fp,-size,SEEK_CUR);//指针移至修改目标前

fwrite(Present,size,1,fp);//将结构体中的内容写入文件

break;//退出循环

}

}

注意,此时的文件的打开方式应改为rt+型(Linux下或UNIX下不用)或者r+型,(反正不能是rb+型)如下所示:

FILE *fp;//设置文件指针

fp = fopen("data", "rt+");//以读写文本格式打开程序目录下已存在的data文件

本帖子中包含资源

您需要 登录 才可以下载,没有帐号?立即注册

C语言实现文件的局部修改,C语言:在文件的指定位置实现局部修改,而无需重写文件的其他部分...相关推荐

  1. R语言ggplot2包和ggtext包在可视化图像中的指定位置添加文本框(横向文本框、竖向文本框)

    R语言ggplot2包和ggtext包在可视化图像中的指定位置添加文本框(横向文本框.竖向文本框) 目录

  2. c语言插入特定的字符串,C语言实现:将一个字符串插入到另一个字符串的指定位置...

    C语言实现:将一个字符串插入到另一个字符串的指定位置 发布时间:2018-08-22 13:23, 浏览次数:1672 示例一: char *insert(char *s1, char *s2, in ...

  3. php 文件指定位置添加内容,C++_VC++在TXT文件指定位置追加内容的方法,本文实例讲述了VC++操作文本文 - phpStudy...

    VC++在TXT文件指定位置追加内容的方法 本文实例讲述了VC++操作文本文件的方法,实现在txt文件指定位置插入内容.对于VC++爱好者有一定的学习参考价值. 主要功能代码如下: void CGoT ...

  4. C语言:在文件的指定位置实现局部修改,而无需重写文件的其他部分

    https://blog.csdn.net/Nolikecake/article/details/103536679

  5. java跨函数跳转_C语言中将绝对地址转换为函数指针以及跳转到内存指定位置处执行的技巧...

    1.方法一 要对绝对地址0x100000赋值,我们可以用 (unsigned int  * ) 0x100000 = 1234; 那么要是想让程序跳转到绝对地址是0x100000去执行,应该怎么做? ...

  6. C语言中将绝对地址转换为函数指针以及跳转到内存指定位置处执行的技巧

    要对绝对地址0x100000赋值,我们可以用       (unsigned int  * ) 0x100000 = 1234;       那么要是想让程序跳转到绝对地址是0x100000去执行,应 ...

  7. 鼠标右键 移动选定的文件夹到指定位置_怎么把电脑桌面上的文件移动到更加安全的地方...

    我们在使用电脑的时候习惯于把各种文档以及其他文件资料随手保存到电脑桌面上,这样操作可以方便以后对这些文档和文件资料的使用.管理,但是由于默认状态下桌面文件位于C盘中,这些文件资料不仅会占用掉C盘的很大 ...

  8. 文件夹目录下所有的视频使用ffmpeg指定位置截图

    代码如下-: import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Scan ...

  9. C语言实现:将一个字符串插入到另一个字符串的指定位置

    示例一: char *insert(char *s1, char *s2, int n) {int len1 = 0, len2 = 0, j = 0, len3, k = 0;char s4[30] ...

最新文章

  1. zz SOA推荐书籍列表
  2. jbpm_工作流框架笔记
  3. 基因表达式编程gep_基因表达式编程GEP— 前言
  4. java 类型不可视_jvm高级特性(5)(1)(原子性,可见性,有序性,volatile,概述)
  5. Team Foundation Server (TFS) 2015 安装指导
  6. HTC ThunderBolt无法打开3G问题解决方法
  7. 软件项目成员的业绩考核
  8. fifa15服务器位置,《FIFA 15》系统菜单界面图文详解 各游戏模式详解
  9. Matplotlib Toolkits:三维绘图工具包matplotlib.mplot3d
  10. [渝粤教育] 西南科技大学 文学概论 在线考试复习资料
  11. 谭浩强 c语言源码下载,谭浩强C语言教材源代码第二章
  12. [从零开始A31S]之安装虚拟机以及下载ubuntu
  13. 七大江河水系--长江(二)
  14. day25:组合总和,电话号码的字母组合
  15. 在线随机密码生成器源码
  16. 当华为云WeLink遇上华为企业智慧屏,端云协同视频会议究竟有多神奇
  17. ef power tools mysql_Entity Framework Code First ---EF Power Tool 和MySql一起使用遇到的问题...
  18. 大数据学习路线,如何学习大数据?
  19. 基于ipk安装包形式移植helloworld驱动模块到openwrt系统
  20. 《如何写好科研论文》2020期末试卷答案

热门文章

  1. 安全帽识别软件能够解决现场管理中的很多问题
  2. r语言和python的区别-Python和R语言之分析对比
  3. 信息学奥林匹克竞赛-编程语言
  4. w7怎么修改计算机用户名,教您电脑用户名怎么修改
  5. 学习ARM开发(1)
  6. CST学习------网格类型及设置方法和技巧
  7. linux系统日志以及分析
  8. 浏览器如何使用HTTP防止ip限制
  9. 用python画一个汉字_python使用reportlab画图示例(含中文汉字)
  10. myEclipse 注册码 在线生成