我有一个 tcl 程序,在其中打开一个文件,如果不存在则创建用于写入。现在我正在其中记录一些 put 语句以进行调试。现在,在此过程结束时,我关闭该文件。但在中间我正在调用另一个过程,我也需要在该过程中的这个打开的文件中写入一些内容。所以我想做这样的事情:
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;
}
Run Code Online (Sandbox Code Playgroud)
那么,当我在 myprocII 中打开同一文件并记录数据并关闭它时,这不是导致错误或异常的原因吗?然后,即使在关闭 myprocII 中的文件后,我仍在调用 proc myproc 中记录数据。我尝试对此进行测试,但由于我是从批处理文件运行它,因此在我弄清楚错误是什么之前窗口会关闭。
所以我想知道这是否正确,或者如果不正确,我如何继续将来自不同程序的数据附加到同一日志文件中。
有以下几种选择:
使用 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}
Run Code Online (Sandbox Code Playgroud)
当程序终止时,Tcl 应该在退出时自行关闭文件。
每次写入时打开/关闭文件。仅在附加模式下有用
proc log {data} {
set fd [open {C:\log.txt} a]
catch {
puts $fd $data
} res opt
close $fd
return -options $opt $res
}
Run Code Online (Sandbox Code Playgroud)
这不是性能最好的解决方案,但它很干净。
使用一些技巧
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
}
Run Code Online (Sandbox Code Playgroud)
C:\log.txt如果已经打开,则返回相同的 fd ,保留引用计数器,当引用计数为 0 时关闭通道
。请注意,这是一个 hack。您可能不应该修改标准命令。