0

我有一个 tcl 程序,我在其中打开了一个文件,如果不存在则创建用于写入。现在我在其中记录了一些 puts 语句以进行调试。现在在这个过程结束时,我关闭了文件。但是在中间我正在调用另一个 proc,我还需要在该 proc 中的这个打开的文件中写入一些东西。所以我想做这样的事情:

proc ::myproc {args} { 
  set fp [open "C:\\log.txt" w+];
  puts $fp "Checkpoint 1";
  set retVal [::myprocII];
  puts $fp "Checkpoint 2";
  close $fp;
  return 1;
}

proc ::myprocII {} {
  set fp [open "C:\\log.txt" w+];
  puts $fp "Checkpoint 3";
  close $fp;
  return 1;
}

因此,当我在 myprocII 中打开同一个文件并记录数据并关闭它时,这不是导致错误或异常的原因。然后,即使在我关闭 myprocII 中的文件后,我仍在调用 proc myproc 中记录数据。我试图对此进行测试,但由于我是从批处理文件中运行它,所以在我弄清楚错误是什么之前窗口就关闭了。

所以我想知道这是否正确,或者如果不是,我如何继续将来自不同过程的数据附加到同一个日志文件中。

4

1 回答 1

4

有几个选项:

  • 使用 1 个文件描述符,在程序结束时关闭它。

    proc log {data} {
        global logfd
        if {![info exists logfd] || $logfd == ""} {
            set logfd [open {C:\log.txt} w]
        }
        puts $logfd $data
    }
    
    # before you exit, close it:
    catch {close $::logfd}
    

    当程序终止时,Tcl 应该在退出时自行关闭文件。

  • 每次写入时打开/关闭文件。仅在附加模式下有用

    proc log {data} {
        set fd [open {C:\log.txt} a]
        catch {
            puts $fd $data
        } res opt
        close $fd
        return -options $opt $res
    }
    

    这不是最高效的解决方案,但它很干净。

  • 使用一些技巧

    rename open _open
    rename close _close
    proc open {path args} {
       global sharedfd
       if {$path eq {C:\log.txt}} {
           if {[info exists sharedfd] && [dict exists $sharedfd fd]} {
               dict incr sharedfd refcount
               return [dict get $sharedfd fd]
           } else {
               set fd [_open $path {*}$args]
               dict set sharedfd fd $fd
               dict set sharedfd refcount 1
               return $fd
           }
       }
       return [_open $path {*}$args]
    }
    
    proc close {fd args} {
        global sharedfd
        if {[info exists sharedfd] 
                && [dict exists $sharedfd fd] 
                && [dict get $sharedfd fd] eq $fd} {
            dict incr sharedfd refcount -1
            if {[dict get $sharedfd refcount] <= 0} {
               _close $fd
               unset sharedfd
            }
            return
        }
        _close $fd {*}$args
    }
    

    C:\log.txt如果它已经打开,则返回相同的 fd ,保留一个 refcounter,当 refcount 为 0 时关闭通道。
    请注意,这是一个 hack。您可能不应该修改标准命令。

于 2013-10-25T16:24:55.000 回答