我的剧本中有这个片段:
puts "Enter Filename:"
set file_name [gets stdin]
set fh [open $file_name r]
#Read from the file ....
close $fh
现在,此代码片段要求用户输入文件名..然后将其设置为输入文件然后读取。但是当名称为$file_name
的文件不存在时,会显示错误
illegal file character
我如何检查fh
是否为空(我不认为tcl中有NULL
的概念是“每个都是字符串”语言!),如果无效给出了file_name,我可以抛出一个说file doesn't exists!
答案 0 :(得分:3)
try {
open $file_name
} on ok f {
# do stuff with the open channel using the handle $f
} on error {} {
error {file doesn't exist!}
}
此解决方案尝试在异常处理程序中打开文件。如果open
成功,则处理程序将运行您在on ok
子句中提供的代码。如果open
失败,处理程序会通过使用您想要的邮件引发新错误来处理该错误(请注意open
可能因其他原因而实际失败)。
try
命令是Tcl 8.6+,对于Tcl 8.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
(in
运算符在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
(在{1}}中添加了chan
命令,将几个与通道相关的命令组合为子命令。如果您使用的是早期版本的Tcl,则可以在不{{1}的情况下调用close
但是你必须为chan
推出自己的替代品。)
try ... finally
子句确保无论文件是否已打开或在执行finally
或on ok
子句期间发生任何错误,都保证该频道不存在当我们离开on error
构造时(变量try
将保留一个不可用的值,除非我们取消它,否则(已销毁或永不创建)。因为我们不知道确定是否存在,我们需要使用f
或catch {unset f}
来防止未设置的操作引发错误。我通常不会打扰:如果我再次使用名称unset -nocomplain f
,我只需要设置这是一个新的价值。)。
文档:catch,chan,close,error,in运营商,file,if,{{ 3}},open,set,try
(这个答案的心脏在正确的地方,但这几个月后我不满意。因为它被三个人接受甚至标记为有用我不愿删除它,但上面的答案是恕我直言更好。)
如果尝试打开不存在的文件并将通道标识符分配给变量,则会引发错误并且变量的内容不会更改。如果该变量不存在,则f
命令不会创建该变量。因此,虽然没有set
值,但您可以1)在打开文件之前将变量设置为您知道不是通道标识符的值:
null
或2)set fh {} ;# no channel identifier is the empty string
set fh [open foo.bar]
if {$fh eq {}} {
puts "Nope, file wasn't opened."
}
变量并在之后测试它是否存在(使用unset
来处理如果变量不存在则引发的错误):
catch
如果要测试文件是否存在,最简单的方法是使用catch {unset fh}
set fh [open foo.bar]
if {![info exists fh]} {
puts "Nope, file wasn't opened."
}
命令:
file exists