Tcl 9.0 如何读取并解压 .tar.gz 归档?
结论
这里有两个独立的问题。普通 .tar 文件的报错与 tcllib tar 0.13 的八进制转换错误有关;.tar.gz 的报错则是因为 zlib push gunzip 提供的解压通道不支持 seek,而 tar 包需要可定位的输入。根据给出的修复信息,tar 0.14 已修复八进制转换问题。读取 gzip 归档时,可以先用 Tcl 将内容解压到临时 tar 文件,再让 tar 包读取这个可 seek 的文件。
更新 tar 包并检查普通 tar 文件
先确认加载的是包含修复的版本:
package require tar 0.14
set entries [::tar::contents package.tar]
puts $entries
报错 expected integer but got "0ush:\n" 是因为 tar 头部的文件大小被错误转换。转换结果出错后,解析器会跳到归档中的错误位置,把后续数据误读为头部。题目给出的修复将转换前缀从 0 改为 0o0,并已包含在 tar 0.14 中。升级后再检查普通 tar 文件。
将 gzip 数据解压到可 seek 的临时文件
不要将经过 zlib push gunzip 转换的通道直接交给需要 seek 的 tar 命令。可以先把解压后的字节写入临时文件:
package require tar 0.14
set input [open package.tar.gz rb]
zlib push gunzip $input
set output [file tempfile tarPath]
fconfigure $output -translation binary -encoding binary
fcopy $input $output
close $output
close $input
try {
set entries [::tar::contents $tarPath]
puts $entries
} finally {
file delete -force $tarPath
}
fcopy 会从经过 gunzip 转换的输入通道读取解压数据,并写入临时文件。关闭文件后,::tar::contents 通过文件路径读取可 seek 的 tar 数据。将代码中的 package.tar.gz 替换为实际归档路径。
解包时的注意事项
上面的代码演示了如何解压并读取归档目录。要将条目写入磁盘,应使用所安装 tar 版本提供的解包接口,并确认该接口所需的输入形式和选项。不要假设 -chan 能让不可 seek 的 gzip 通道变为可 seek。原 shell 命令还使用了 --strip-components 1;tar 包的接口是否支持这一选项,需要根据该版本的接口确认。如果仍使用外部 tar 命令,可以将解压后的临时 tar 文件路径传给它,并在使用后清理临时文件。
备注:内容仅供参考。
