Tcl 编程/文件操作
除了 C 语言中的 stdio 库中已知的功能外,Tcl 还提供了一些用于处理文件的命令,类似于 Shell 提供的功能,尽管通常更冗长。以下是一些示例
glob *.tcl
列出当前目录中与模式 *.tcl 匹配的所有文件。
file copy /from/path/file.ext /to/path . file delete /from/path/file.ext . file rename before.txt after.txt . cd /an/other/directory . pwd
要让代码在另一个目录中临时执行,可以使用此模式
set here [pwd] cd $someotherdir #... code here cd $here
更准确地说,许多“文件”操作通常在“通道”上工作,它们可以是
- 标准通道 (stdin、stdout、stderr)
- 使用 open ... 打开的文件
- 使用 'open |... 打开的管道
- 套接字 (TCP)
文件通常使用路径名来访问,它指示它们在目录树中的位置。与 Unix 一样,Tcl 使用 "/" 作为路径分隔符,而在 Windows 上 "\" 是本机方式 - 这不仅会给 Tcl 带来麻烦,甚至会给 C 带来麻烦,因为 "\" 在两者中都是转义字符,因此例如 \t 被解析为水平制表符,\n 被解析为换行符等。幸运的是,Windows 本机也接受 "/",因此您可以在 Tcl 和 C 程序中使用正斜杠作为路径分隔符,而无需担心。但是,您仍然需要注意转义序列。一个权宜之计是
- 转义转义字符,即为 \, 写 \\,或
- 将反斜杠名称括起来,例如 {\foo\bar\grill.txt}
但 Tcl 允许在几乎所有情况下使用“正常”分隔符 /,所以使用它更安全。不幸的是,对于 Mac 用户来说,情况很糟糕,因为 MacOS(在 X 之前)只接受 ":" 作为文件分隔符。
如果您需要,以下是如何在两种形式之间转换
% file normalize \\foo\\bar\\grill.txt C:/foo/bar/grill.txt % file nativename /foo/bar/grill.txt \foo\bar\grill.txt
您甚至可以使用 file join 命令:file join arg1 arg2 ... argN
然后 Tcl 会处理所有平台相关细节以创建平台无关路径。例如
set somepath [file join foo bar grill.txt]
将在以下路径 (在 Windows 机器上) 上产生结果:foo/bar/grill.txt
Tcl 的输入/输出命令与 C 语言的 stdio 中的命令非常接近(只需去掉开头的 f)
- set handle [open filename ?mode?]
- set data [read $handle ?int?]
- tell $handle
- seek $handle offset ?from?
- puts ?-nonewline? ?$handle? content
- gets $handle ?varname?
- close $handle
C 语言的 printf 功能分为两步
- 使用 format 将数据格式化为字符串(非常类似于 sprintf)
- 使用 puts 输出生成的字符串。例如,
puts $handle [format "%05d %s" $number $text]
要逐行处理文本文件,您有两种选择。如果文件小于几兆字节,您可以一次性将其读入
set f [open $filename] foreach line [split [read $f] \n] { # work with $line here ... } close $f
对于任何大小的文件,您可以逐行读取(尽管这比上面的方法稍微慢一些)
set f [open $filename] while {[gets $f line] >= 0} { # work with $line here ... } close $f
最后,如果您能将文件格式化为可执行的 Tcl 代码,以下读取方法最快
source $filename
要“触摸一个文件”,即如果不存在则创建它,并且在任何情况下更新它的修改时间,您可以使用此方法
proc touch name {close [open $name a]}
所有文件都由字节组成,字节由位组成,位是二进制的。术语“二进制”与文件的关系主要在于它们可以包含任何值的字节,并且行结束符 (DOS/Windows 世界中的回车符 + 换行符) 不会被转换。Tcl 可以毫无问题地处理“二进制”文件 - 只需在打开后将通道配置为二进制
set fp [open tmp.jpg] fconfigure $fp -translation binary set content [read $fp] close $fp
现在变量 content 按字节保存文件的内容。
要测试文件是否为“二进制”,即它是否包含 NUL 字节
proc binary? filename { set f [open $filename] set data [read $f 1024] close $f expr {[string first \x00 $data]>=0} }
许多有用的文件操作都集中在 file 命令中。第一个参数告诉要执行哪个操作
- file atime name ?time?
- file attributes name
- file attributes name ?option?
- file attributes name ?option value option value...?
- file channels ?pattern? - 返回当前打开文件的句柄
- file copy ?-force? ?- -? source target
- file copy ?-force? ?- -? source ?source ...? targetDir
- file delete ?-force? ?- -? pathname ?pathname ... ?
- file dirname name - 例如 [file dirname /foo/bar/grill.txt] -> /foo/bar
- file executable name
- file exists name
- file extension name - 例如 [file extension /foo/bar/grill.txt] -> .txt
- file isdirectory name
- file isfile name
- file join name ?name ...?
- file link ?-linktype? linkName ?target?
- file lstat name varName
- file mkdir dir ?dir ...? - 创建一个或多个目录(文件夹)
- file mtime name ?time?
- file nativename name
- file normalize name
- file owned name
- file pathtype name
- file readable name
- file readlink name
- file rename ?-force? ?- -? source target
- file rename ?-force? ?- -? source ?source ...? targetDir
- file rootname name - 例如 [file rootname /foo/bar/grill.txt] -> /foo/bar/grill
- file separator ?name?
- file size name
- file split name - 例如 [file split /foo/bar/grill.txt] -> {foo bar grill.txt}
- file stat name varName
- file system name
- file tail name - 例如 [file tail /foo/bar/grill.txt] -> grill.txt
- file type name
- file volumes - Windows:返回您的“驱动器号”,例如 {A:/ C:/}
- file writable name