如何修改文件中间的几个字节

工作中碰到一个问题,如何只修改文件中间的几个字节,而其他的内容不变。这个问题看似简单,但是很多人估计都不知道怎么做。我开始seek到文件的特定的位置,然后写文件,但是使用的文件打开模式不对,文件不是被清空,就是被截断,达不到效果。

fopen的打开模式

在C语言中文件打开方式有这么几种:

  • r   以只读方式打开文件,只能读不能写,往文件中写是没有任何效果的
  • r+  可以读,也可以写,文件打开的时候,指向文件开头,可以通过seek改变读写位置
  • w  这种方式打开的文件句柄,只能写,如果文件存在则将长度清零,否则新建文件,这种句柄通过seek之后,seek位置之前的文件数据全部变成0x00
  • w+ 同w选项,只不过多了一个可读功能
  • a  这种方式打开的文件,可以写,但是位置在文件末尾,即使往回seek也没有用,数据还是从文件末尾开始附加
  • a+ 同a选项,多了可读的功能

另外还有2个选项,可以与上面的6个选项复合使用,一个是t表示以文本的方式打开文件(默认是t),一个是b表示以二进制的方式打开文件,t和b是互斥的不能同时使用。当与b组合时,有这么几种方式:wb、ab、rb、wb+、ab+、rb+,而a,w,r这几个选项是不能组合使用的,其中a,w都表示写文件,只不过一个在文件尾,一个在文件开始处,r表示读文件。我试过将a,w,r几个两两组合使用,发现下面的现象:

  • wr 与w效果一样
  • rw与r效果一样
  • aw与a效果一样
  • wa 与w效果一样
  • ar与a效果一样
  • ra与r效果一样

可以看出来当a,w,r在一起组合使用的时候,其后面的选项实际上好像是被忽略了

问题的解决方法:rb+打开文件

所以解决文章开头提出来的问题,应该使用  rb+ 的方式打开文件,这种方式打开的文件,可读,可写,打开之后写指针在文件开始处,可以任意seek,而seek之后写的内容会覆盖被写的内容,其他没有写到的内容不会有改变。

测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//程序测试结果在ubuntu linux下运行获得
#include <stdio.h>
#include <string.h>
int main()
{
   //文件原始数据
   //00 01 02 03 04 05 06 07 08 09
 
   //下面每一个fopen前面注释中的数据是以该方式打开文件,写文件之后文件的内容
      
   //00 00 00 00 CC DD
   //FILE * file = fopen("./test.data","wb+");
    
   //00 00 00 00 CC DD
   //FILE * file = fopen("./test.data","wb");
    
   //00 01 02 03 CC DD 06 07 08 09
   FILE * file = fopen("./test.data","rb+"); //这种是正确的做法
    
   //00 01 02 03 04 05 06 07 08 09
   //FILE * file = fopen("./test.data","rb");
    
   //00 01 02 03 04 05 06 07 08 09 CC DD
   //FILE * file = fopen("./test.data","ab");
    
   //00 01 02 03 04 05 06 07 08 09 CC DD
   //FILE * file = fopen("./test.data","ab+");
    
   //00 00 00 00 CC DD
   //FILE * file = fopen("./test.data","wr");
    
   //00 01 02 03 04 05 06 07 08 09
   //FILE * file = fopen("./test.data","rw");
    
   //00 01 02 03 04 05 06 07 08 09 CC DD
   //FILE * file = fopen("./test.data","aw");
    
   //00 00 00 00 CC DD
   //FILE * file = fopen("./test.data","wa");
    
   //00 01 02 03 04 05 06 07 08 09 CC DD
   //FILE * file = fopen("./test.data","ar");
    
   //00 01 02 03 04 05 06 07 08 09
   //FILE * file = fopen("./test.data","ra");
   if(file!=NULL)
   {
      char buffer[]={0xCC,0xDD};
      fseek(file,4,SEEK_SET);
      fwrite(buffer,1,sizeof(buffer),file);
      fclose(file);
   }
   return 0;
}

 

posted @   薰衣草的旋律  阅读(3585)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示