原文: https://zetcode.com/lang/tcl/io/

在本章中,我们将使用 Tcl 中的输入和输出操作。 Tcl 有几个执行 io 的命令。 我们将介绍其中的一些。

Tcl 使用称为通道的对象读取和写入数据。 可以使用opensocket命令创建通道。 Tcl 脚本可使用三个标准通道,而无需显式创建它们。 操作系统会为每个新应用自动打开它们。 它们是stdinstdoutstderr。 脚本使用标准输入stdin来读取数据。 脚本使用标准输出stdout写入数据。 脚本使用标准错误stderr来编写错误消息。

在第一个示例中,我们将使用puts命令。 它具有以下概要:

  1. puts ?-nonewline? ?channelId? string

channelId是我们要在其中写入文本的通道。 channelId是可选的。 如果未指定,则采用默认值stdout

  1. #!/usr/bin/tclsh
  2. puts "Message 1"
  3. puts stdout "Message 2"
  4. puts stderr "Message 3"

puts命令将文本写入通道。

  1. puts "Message 1"

如果未指定channelId,则默认情况下写入stdout

  1. puts stdout "Message 2"

此行与上一行相同。 我们仅明确指定了channelId

  1. puts stderr "Message 3"

我们写入标准错误通道。 错误消息默认情况下转到终端。

  1. $ ./printing.tcl
  2. Message 1
  3. Message 2
  4. Message 3

示例输出。

read命令

read命令用于从通道读取数据。 可选参数指定要读取的字符数。 如果省略,该命令将从通道读取所有数据,直到最后。

  1. #!/usr/bin/tclsh
  2. set c [read stdin 1]
  3. while {$c != "q"} {
  4. puts -nonewline "$c"
  5. set c [read stdin 1]
  6. }

该脚本从标准输入通道读取一个字符,然后将其写入标准输出,直到遇到q字符为止。

  1. set c [read stdin 1]

我们从标准输入通道(stdin)读取一个字符。

  1. while {$c != "q"} {

我们继续读取字符,直到按q为止。

gets命令

gets命令从通道读取下一行,返回行中直到(但不包括)行尾字符的所有内容。

  1. #!/usr/bin/tclsh
  2. puts -nonewline "Enter your name: "
  3. flush stdout
  4. set name [gets stdin]
  5. puts "Hello $name"

该脚本要求用户输入,然后打印一条消息。

  1. puts -nonewline "Enter your name: "

puts命令用于将消息打印到终端。 -nonewline选项禁止换行符。

  1. flush stdout

Tcl 缓冲区在内部输出,因此用puts编写的字符可能不会立即出现在输出文件或设备上。 flush命令强制输出立即显示。

  1. set name [gets stdin]

gets命令从通道读取一条线。

  1. $ ./hello.tcl
  2. Enter your name: Jan
  3. Hello Jan

脚本的示例输出。

pwdcd命令

Tcl 具有pwdcd命令,类似于 shell 命令。 pwd命令返回当前工作目录,cd命令用于更改工作目录。

  1. #!/usr/bin/tclsh
  2. set dir [pwd]
  3. puts $dir
  4. cd ..
  5. set dir [pwd]
  6. puts $dir

在此脚本中,我们将打印当前工作目录。 然后,我们更改工作目录并再次打印工作目录。

  1. set dir [pwd]

pwd命令返回当前工作目录。

  1. cd ..

我们将工作目录更改为当前目录的父目录。 我们使用cd命令。

  1. $ ./cwd.tcl
  2. /home/janbodnar/prog/tcl/io
  3. /home/janbodnar/prog/tcl

样本输出。

glob命令

Tcl 具有glob命令,该命令返回与模式匹配的文件的名称。

  1. #!/usr/bin/tclsh
  2. set files [glob *.tcl]
  3. foreach file $files {
  4. puts $file
  5. }

该脚本将所有带有.tcl扩展名的文件打印到控制台。

  1. set files [glob *.tcl]

glob命令返回与*.tcl模式匹配的文件列表。

  1. foreach file $files {
  2. puts $file
  3. }

我们浏览文件列表,并将列表的每个项目打印到控制台。

  1. $ ./globcmd.tcl
  2. attributes.tcl
  3. allfiles.tcl
  4. printing.tcl
  5. hello.tcl
  6. read.tcl
  7. files.tcl
  8. globcmd.tcl
  9. write2file.tcl
  10. cwd.tcl
  11. readfile.tcl
  12. isfile.tcl
  13. addnumbers.tcl

这是globcmd.tcl脚本的示例输出。

处理文件

file命令操纵文件名和属性。 它有很多选择。

  1. #!/usr/bin/tclsh
  2. puts [file volumes]
  3. [file mkdir new]

该脚本将打印系统的已安装卷,并创建一个新目录。

  1. puts [file volumes]

file volumes命令返回到系统上安装的卷的绝对路径。

  1. [file mkdir new]

file mkdir创建一个名为new的目录。

  1. $ ./voldir.tcl
  2. /
  3. $ ls -d */
  4. doc/ new/ tmp/

在 Linux 系统上,有一个已安装的卷-根目录。 ls命令确认new目录的创建。

在下面的代码示例中,我们将检查文件名是常规文件还是目录。

  1. #!/usr/bin/tclsh
  2. set files [glob *]
  3. foreach fl $files {
  4. if {[file isfile $fl]} {
  5. puts "$fl is a file"
  6. } elseif { [file isdirectory $fl]} {
  7. puts "$fl is a directory"
  8. }
  9. }

我们遍历当前工作目录中的所有文件名,并打印它是文件还是目录。

  1. set files [glob *]

使用glob命令,我们创建当前目录的文件和目录名称的列表。

  1. if {[file isfile $fl]} {

如果有问题的文件名是文件,我们将执行if命令的主体。

  1. } elseif { [file isdirectory $fl]} {

file isdirectory命令确定文件名是否为目录。 请注意,在 Unix 上,目录是文件的特例。

puts命令可用于写入文件。

  1. #!/usr/bin/tclsh
  2. set fp [open days w]
  3. set days {Monday Tuesday Wednesday Thursday Friday Saturday Sunday}
  4. puts $fp $days
  5. close $fp

在脚本中,我们打开一个文件进行写入。 我们将一周中的几天写入文件。

  1. set fp [open days w]

我们打开一个名为days的文件进行写入。 open命令返回一个通道 ID。

  1. set days {Monday Tuesday Wednesday Thursday Friday Saturday Sunday}

该数据将被写入文件。

  1. puts $fp $days

我们使用open命令返回的通道 ID 写入文件。

  1. close $fp

我们关闭打开的频道。

  1. $ ./write2file.tcl
  2. $ cat days
  3. Monday Tuesday Wednesday Thursday Friday Saturday Sunday

我们运行脚本并检查days文件的内容。

在下面的脚本中,我们将从文件中读取数据。

  1. $ cat languages
  2. Python
  3. Tcl
  4. Visual Basic
  5. Perl
  6. Java
  7. C
  8. C#
  9. Ruby
  10. Scheme

我们在目录中有一个简单的文件,称为语言。

  1. #!/usr/bin/tclsh
  2. set fp [open languages r]
  3. set data [read $fp]
  4. puts -nonewline $data
  5. close $fp

我们从提供的文件中读取数据,读取其内容,然后将数据打印到终端。

  1. set fp [open languages r]

我们通过以只读模式打开语言文件来创建频道。

  1. set data [read $fp]

如果我们没有为read命令提供第二个参数,它将从文件中读取所有数据,直到文件结尾。

  1. puts -nonewline $data

我们将数据打印到控制台。

  1. $ ./readfile.tcl
  2. Python
  3. Tcl
  4. Visual Basic
  5. Perl
  6. Java
  7. C
  8. C#
  9. Ruby
  10. Scheme

readfile.tcl脚本的示例运行。

eof命令检查所提供通道的行尾。

  1. #!/usr/bin/tclsh
  2. set fp [open languages]
  3. while {![eof $fp]} {
  4. puts [gets $fp]
  5. }
  6. close $fp

我们使用eof命令读取文件的内容。

  1. while {![eof $fp]} {
  2. puts [gets $fp]
  3. }

循环继续进行,直到eof遇到文件结尾都返回true为止。 在体内,我们使用gets命令从文件中读取一行。

  1. $ ./readfile2.tcl
  2. Python
  3. Tcl
  4. Visual Basic
  5. Perl
  6. Java
  7. C
  8. C#
  9. Ruby
  10. Scheme

readfile2.tcl脚本的示例运行。

下一个脚本将执行一些其他文件操作。

  1. #!/usr/bin/tclsh
  2. set fp [open newfile w]
  3. puts $fp "this is new file"
  4. flush $fp
  5. file copy newfile newfile2
  6. file delete newfile
  7. close $fp

我们打开一个文件,并在其中写入一些文本。 文件被复制。 然后删除原始文件。

  1. file copy newfile newfile2

file copy命令复制文件。

  1. file delete newfile

原始文件用file delete命令删除。

在最后一个示例中,我们将使用文件属性。

  1. #!/usr/bin/tclsh
  2. set files [glob *]
  3. set mx 0
  4. foreach fl $files {
  5. set len [string length $fl]
  6. if { $len > $mx} {
  7. set mx $len
  8. }
  9. }
  10. set fstr "%-$mx\s %-s"
  11. puts [format $fstr Name Size]
  12. set fstr "%-$mx\s %d bytes"
  13. foreach fl $files {
  14. set size [file size $fl]
  15. puts [format $fstr $fl $size]
  16. }

该脚本将创建两列。 在第一列中,我们有文件的名称。 在第二列中,我们显示文件的大小。

  1. foreach fl $files {
  2. set len [string length $fl]
  3. if { $len > $mx} {
  4. set mx $len
  5. }
  6. }

在此循环中,我们找出了最长的文件名。 格式化输出列时将使用此格式。

  1. set fstr "%-$mx\s %-s"
  2. puts [format $fstr Name Size]

在这里,我们打印列的标题。 要格式化数据,我们使用format命令。

  1. set fstr "%-$mx\s %d bytes"
  2. foreach fl $files {
  3. set size [file size $fl]
  4. puts [format $fstr $fl $size]
  5. }

我们遍历文件列表并打印每个文件名及其大小。 file size命令确定文件的大小。

  1. $ ./attributes.tcl
  2. Name Size
  3. attributes.tcl 337 bytes
  4. newfile2 17 bytes
  5. allfiles.tcl 75 bytes
  6. printing.tcl 83 bytes
  7. languages 51 bytes
  8. hello.tcl 109 bytes
  9. days 57 bytes
  10. read.tcl 113 bytes
  11. files.tcl 140 bytes
  12. globcmd.tcl 82 bytes
  13. write2file.tcl 134 bytes
  14. doc 4096 bytes
  15. cwd.tcl 76 bytes
  16. tmp 4096 bytes
  17. readfile.tcl 98 bytes
  18. isfile.tcl 219 bytes

样品运行。

在本章中,我们介绍了 Tcl 中的输入/输出操作。