跳转到内容

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 命令中。第一个参数告诉要执行哪个操作

  • 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
华夏公益教科书