【问题标题】:Tcl strings to middle of binary file without overwriting its contenTcl 字符串到二进制文件的中间而不覆盖其内容
【发布时间】:2021-06-12 19:44:06
【问题描述】:

我有一个二进制文件 我试图在文件中间添加一个字符串 (让我们说在 10 个字节之后)

我成功地用我的字符串覆盖了文件 - 但不是追加 如果有人能告诉我如何附加字符串,不胜感激。

这是我的代码示例:

proc write_bit_header {} {
    set bit_hdr "#Here is my new string to be added#"
    set bit_hdr_len [string length ${bit_hdr}]
    set outBinData [binary format a${bit_hdr_len} ${bit_hdr}]

    set fp [open "binfile"  "a+b"]
    fconfigure $fp -translation binary
    seek $fp 10
    puts -nonewline $fp $outBinData
    close $fp
}

【问题讨论】:

    标签: file binary tcl


    【解决方案1】:

    当您写入文件的中间时(您将使用r+b模式),文件中的其他字节都不会移动.它们在文件中的偏移量仍然与之前完全相同。如果您将固定大小的二进制记录写入文件,这正是您想要的!但是,如果您要编写可变大小的记录,则必须:

    1. 读取所有要写入的字节之后的数据
    2. 寻找你想要插入/替换的地方
    3. 写入要插入的数据
    4. 写入您在步骤 1 中读取的数据
    5. 截断文件(以防您在第 3 步中写入的内容比您要替换的内容短)。

    是的,这很重要!

    proc insertData {filename dataToInsert insertionPoint {firstAfterByte ""}} {
        # If you don't give the end of the range to overwrite, it's zero-length
        if {$firstAfterByte eq ""} {
            set firstAfterByte $insertionPoint
        }
    
        set f [open $filename "r+b"]
        chan seek $f $firstAfterByte
        set suffixData [chan read $f]
        chan seek $f $insertionPoint
        chan puts -nonewline $f $dataToInsert
        chan puts -nonewline $f $suffixData
        chan truncate $f
        close $f
    }
    

    追加时要容易得多,因为您不必移动任何现有数据,也无需截断。并且您可以使用ab 模式,这样您就不需要显式地seek

    proc appendData {filename dataToAppend} {
        set f [open $filename "ab"]
        puts -nonewline $f $dataToAppend
        close $f
    }
    

    如您所见,插入代码要复杂得多。它也有很大的出错风险。最好使用工作副本文件,然后在最后替换原始文件:

    proc insertDataSafely {filename dataToInsert insertionPoint {firstAfterByte ""}} {
        set f_in [open $filename "rb"]
        set f_out [open ${filename}.tmp "wb"]
        try {
            chan copy $f_in $f_out $insertionPoint
            puts -nonewline $f_out $dataToInsert
            if {$firstAfterByte ne ""} {
                chan seek $f_in $firstAfterByte
            }
            chan copy $f_in $f_out
            chan close $f_in
            chan close $f_out
        } on ok {} {
            file rename ${filename}.tmp $filename
        } on error {msg opt} {
            file delete ${filename}.tmp
            # Reraise the error
            return -options $opt $msg
        }
    }
    

    当然,并不是所有的文件都对这种事情一开始就接受,但是修改任意文件会使事情变得混乱的方式很长,而且完全超出了这个问题的范围。

    【讨论】:

    • 需要特别注意的是,打开文件的其他程序可能会非常惊讶地发现它们下面的内容发生了变化(除了 append 的情况,它更安全、更安全)对日志文件的工作方式非常关键……)
    • 您好,Donal 感谢您的回答 - 它成功了。
    • 一件小事:“chan copy”需要“-size”才能为我工作:chan copy $f_in $f_out -size $insertionPoint 谢谢,Moshe
    猜你喜欢
    • 1970-01-01
    • 2012-05-15
    • 2011-12-16
    • 2019-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    相关资源
    最近更新 更多