如何使用Tcl在二进制文件中间插入字符串且不覆盖原有内容
二进制文件中间插入字符串的正确实现方式
现有代码的核心问题
- 打开文件的模式选择错误:
a+b是追加读写模式,底层带O_APPEND标志,无论调用seek把文件指针移到哪个位置,写操作都会被强制定位到文件末尾执行,根本无法写入到指定的中间位置 - 缺少原有内容位移步骤:磁盘上的文件是连续存储的字节序列,没有办法直接在文件中间“撑开”一段空余空间写入新内容,直接在目标位置写入的话,必然会覆盖偏移位置之后的原有内容
正确实现流程
- 选用
r+b模式打开已有文件,这个模式支持在不截断文件的前提下自由读写任意位置,不会强制将写操作固定到文件末尾 - 提前通过
fconfigure设置二进制翻译模式,避免跨平台时的换行符转换破坏二进制内容 - 将文件指针定位到目标插入偏移位置,把该位置之后的所有原有内容完整读取到内存临时存储
- 将文件指针向后偏移新字符串的长度,把临时存储的原有内容写入该位置,实现插入点之后内容的整体后移
- 再次将文件指针调回最初的插入偏移位置,写入待插入的新字符串
- 操作完成后关闭文件
如果处理体积特别大的二进制文件,一次性把插入点后的全量内容读到内存会占用过高内存,可以调整为固定大小分块读写的方式,逐块向后移动数据,降低内存峰值。
修正后的可运行代码
proc write_bit_header {} { set bit_hdr "#Here is my new string to be added#" set insert_offset 10 ;# 插入位置为第10字节之后,对应文件偏移量10 set bit_hdr_len [string length $bit_hdr] set outBinData [binary format a${bit_hdr_len} $bit_hdr] ;# 以读写不截断模式打开文件 set fp [open "binfile" "r+b"] fconfigure $fp -translation binary ;# 读取插入点之后的全部原有内容 seek $fp $insert_offset set origin_after_data [read $fp] ;# 将原有内容整体后移新字符串的长度 seek $fp [expr {$insert_offset + $bit_hdr_len}] puts -nonewline $fp $origin_after_data ;# 在插入位置写入新字符串 seek $fp $insert_offset puts -nonewline $fp $outBinData close $fp }
注意:如果文件总体积远大于可用内存,不建议一次性全量读取文件内容,可通过分块读写优化:每次读取固定大小(如4MB)的数据块,逐块写入到后移后的目标位置,避免内存溢出。
内容的提问来源于stack exchange,提问作者Moshe Raz
相关产品推荐
相关产品推荐

