文本文件处理 for Tcler: 文件路径

谈文本文件处理,少不了对文件路径的处理。

Linux 下文件的路径形如 /home/user/my-file.txt

Windows 下文件的路径形如 C:\home\user\my-file.txt

文件目录层次

文件路径实际上表示了一个目录层次结构。

  1. 一个文件是从属于一个目录的
  2. 一个目录是从属于它的父目录的
  3. 如此递归,直到最顶层的目录,称之为根目录

file isfile 和 file isdir

可以判断一个文件路径是文件还是目录

file isfile /path/to/my-file.txt
file isdir  /path/to/my-file.txt

也可以直接获取路径的文件类型

file type /path/to/some/file/or/directory

file dir 和 file tail

一个文件路径可以分为目录部分和文件部分。

在 Tcl 里,对应 file dirfile tail 两个命令

set file_path /home/user/my-file.txt

set file_dir [file dir $file_path]
## file_dir = /home/user

set file_name [file tail $file_path]
## file_name = my-file.txt

文件名和文件后缀

历史原因,文件名中最后一个点 . 之后的部分是文件名后缀,用来表明文件的类型。

在图形桌面环境下,鼠标双击一个文件时,操作系统根据文件名后缀决定用哪个程序打开这个文件。

file root 和 file tail

文件路径也可以看作是由文件名后缀和其之前的文件路径前缀组成。

set file_path /home/user/my-file.txt

set file_ext [file extension $file_path]
## file_ext = .txt

set file_root [file root $file_path]
## file_root = /home/user/my-file

很多时候,多个有关联的文件只是文件名后缀不一样。可以利用 file root 命令从一个已知路径计算相关的文件路径。

set file_path /home/user/my-file.txt
set log_file [file root $file_path].log
## log_file = /home/user/my-file.log

相对路径与完整路径

为了使用方便,操作系统有一个当前目录的概念。

以当前目录为基准的话,只需要使用所谓的 相对路径 就可以制定文件的位置。

相对路径和完整路径之间就有一个转换的问题

set cwd [pwd]   ;# 当前工作路径

set fullpath  [file join $cwd my-file.txt]
set localpath [string range $fullpath [string length $cwd]+1 end]

file join 和 file separator

file join 命令的存在可以掩盖不同操作系统的文件路径分隔符不一样这个问题。

set fullpath  [file join $cwd my-file.txt]
# 等效于
set fullpath $cwd[file separator]my-file.txt

其中的 file separator 命令用于获取当前系统的文件路径分隔符。

计算相对路径

上面例子中从完整路径计算相对路径用到了 string range 命令,看起来不够优雅。

自己实现一个 file-path 命令整合封装以下全路径和相对路径的计算。

proc file-path {path {cwd "."}} {
  if {$cwd eq "/"} {
    # 计算全路径
    return [file join [pwd] $path]
  } else {
    # 计算相对路径
    if {$cwd eq "."} {
      set cwd [pwd]
    }
    set cwd  [file dir [file normalize $cwd/dummy]]
    set path [file normalize $path]
    return [string range $path [string length $cwd]+1 end]
  }
}

绝对路径

上面的代码中用到了 file normalize 这个命令。

这就引出了 绝对路径 和 全路径 这两种概念上的区分。

全路径虽然也是从根目录开始,但路径中的某些部分可能不是那么规范。

这个命令有三方面的作用

  1. 把相对路径转换为绝对路径
  2. 整理全路径中的 /.//../ 以及 // 这样的不规范部分
  3. 解析路径中 symbol link 的部分