如何检查tcl中文件句柄的值是否为空
我的脚本中有以下代码片段:如何检查tcl中文件句柄的值是否为空,tcl,Tcl,我的脚本中有以下代码片段: puts "Enter Filename:" set file_name [gets stdin] set fh [open $file_name r] #Read from the file .... close $fh 现在,此代码段要求用户输入文件名。。然后将其设置为输入文件,然后读取。但是当名为$file\u name的文件不存在时,它会显示错误消息 illegal file character 如何检查fh是否不为null(我认为tcl中没有nul
puts "Enter Filename:"
set file_name [gets stdin]
set fh [open $file_name r]
#Read from the file ....
close $fh
现在,此代码段要求用户输入文件名。。然后将其设置为输入文件,然后读取。但是当名为$file\u name
的文件不存在时,它会显示错误消息
illegal file character
如何检查fh
是否不为null(我认为tcl中没有null
的概念是“everyting is a string”语言!),这样,如果给出了无效的文件名,我就可以抛出一个打印,说文件不存在代码>简短回答:
此解决方案尝试在异常处理程序中打开文件。如果open
成功,处理程序将在on ok
子句中运行您给它的代码。如果open
失败,处理程序将通过使用您想要的消息引发新错误来处理该错误(请注意,open
也可能由于其他原因而实际失败)
try
命令是tcl8.6+,对于tcl8.5或更早版本,请参阅详细答案
长答覆:
打开一个文件可能会因为几个原因而失败,包括缺少文件或权限不足。某些语言允许文件打开函数返回指示失败的特殊值。包括Tcl在内的其他公司则通过根本不让open
返回而引发异常来发出故障信号。在最简单的情况下,这意味着可以编写脚本,而不必考虑这种可能性:
set f [open nosuchf.ile]
# do stuff with the open channel using the handle $f
# run other code
在执行open
命令时,此脚本将以错误消息终止
脚本不必因此而终止。只有在open
命令成功时,才能截获异常并使使用文件句柄的代码执行:
if {![catch {open nosuchf.ile} f]} {
# do stuff with the open channel using the handle $f
}
# run other code
(catch
命令是Tcl 8.5及更早版本中使用的一个不太复杂的异常处理程序。)
即使open
失败,此脚本也不会过早终止,但在这种情况下,它也不会尝试使用$f
。不管发生什么,“其他代码”都将运行
如果希望“其他代码”知道open
操作是否失败或成功,可以使用以下构造:
if {![catch {open nosuchf.ile} f]} {
# do stuff with the open channel using the handle $f
# run other code in the knowledge that open succeeded
} else {
# run other code in the knowledge that open failed
}
# run code that doesn't care whether open succeeded or failed
或者可以检查变量f
的状态:
catch {open nosuchf.ile} f
if {$f in [file channels $f]} {
# do stuff with the open channel using the handle $f
# run other code in the knowledge that open succeeded
} else {
# run other code in the knowledge that open failed
}
# run code that doesn't care whether open succeeded or failed
(Tcl 8.5+中有操作符;如果您有早期版本,则需要以另一种方式编写测试。无论如何,您不应该使用早期版本,因为它们不受支持。)
此代码检查f
的值是否是解释器知道的开放通道之一(如果不是,该值可能是错误消息)。这不是一个优雅的解决方案
确保频道关闭
这与问题无关,但却是一个良好的实践
try {
open nosuchf.ile
} on ok f {
# do stuff with the open channel using the handle $f
# run other code in the knowledge that open succeeded
} on error {} {
# run other code in the knowledge that open failed
} finally {
catch {chan close $f}
}
# run code that doesn't care whether open succeeded or failed
(Tcl 8.5中添加了chan
命令,以将多个与频道相关的命令分组为子命令。如果您使用的是早期版本的Tcl,您可以在不使用chan
的情况下调用close
,但您必须自行替换try…finally
)
finally
子句确保在执行on ok
或on error
子句期间,无论文件是否打开或是否发生任何错误,当我们离开try
构造时,通道都保证不存在(已销毁或从未创建)(变量f
将保留一个不可用的值,除非我们取消设置它。由于我们不确定它是否存在,我们需要使用catch{unset f}防止unset操作引发错误
或取消设置-nocomplain f
。我通常不麻烦:如果我再次使用名称f
,我只是将其设置为一个新值。)
文档:,,运算符
旧答案:
(这个答案的核心是正确的,但几个月后我对它并不满意。因为它被三个人接受,甚至被标记为有用,我不愿意删除它,但上面的答案更好。)
如果试图打开不存在的文件并将通道标识符分配给变量,则会引发错误,变量的内容将保持不变。如果变量不存在,则不会通过set
命令创建该变量。因此,虽然没有null
值,但可以选择1)在打开文件之前,将变量设置为您知道不是通道标识符的值:
set fh {} ;# no channel identifier is the empty string
set fh [open foo.bar]
if {$fh eq {}} {
puts "Nope, file wasn't opened."
}
或2)unset
变量,然后测试它是否存在(使用catch
处理变量不存在时引发的错误):
如果要测试文件是否存在,最简单的方法是使用file exists
命令:
file exists $file_name
if {![file exists $file_name]} {
puts "No such file"
}
文档:,,,请注意,我在您接受答案后添加到了答案中。
catch {unset fh}
set fh [open foo.bar]
if {![info exists fh]} {
puts "Nope, file wasn't opened."
}
file exists $file_name
if {![file exists $file_name]} {
puts "No such file"
}