我正在尝试实现一个读取文本文件的tcl脚本,并屏蔽包含它的所有敏感信息(如密码,IP地址等)并将输出写入另一个文件。
截至目前,我只是用 * *或#####替换此数据,并使用regexp搜索整个文件,以找到我需要屏蔽的内容。但由于我的文本文件可能是100K行或更多行,因此效率极低。
我是否可以使用内置的tcl函数/命令来更快地完成此操作?任何附加软件包都提供额外的选项,可以帮助完成这项工作吗?
注意:我正在使用tcl 8.4(但如果有更新版本的tcl有办法,请指点我们)
答案 0 :(得分:2)
一般来说,您应该将代码放在一个程序中,以便从Tcl中获得最佳性能。 (你在8.5和8.6中有一些更多的相关选项,比如lambda术语和类方法,但它们与程序密切相关。)你还应该注意其他一些事情:
expr {$a + $b}
而不是expr $a + $b
)中,因为这样可以实现更有效的编译策略。fconfigure $chan -translation binary
,该频道将传输字节而非字符。但是,gets
在面向字节的频道上效率不高在8.4中。使用-encoding iso8859-1 -translation lf
将带来大部分好处。)进行面向行的转换的惯用方法是:
proc transformFile {sourceFile targetFile RE replacement} {
# Open for reading
set fin [open $sourceFile]
fconfigure $fin -encoding iso8859-1 -translation lf
# Open for writing
set fout [open $targetFile w]
fconfigure $fout -encoding iso8859-1 -translation lf
# Iterate over the lines, applying the replacement
while {[gets $fin line] >= 0} {
regsub -- $RE $line $replacement line
puts $fout $line
}
# All done
close $fin
close $fout
}
如果文件足够小以至于它可以很容易地放入内存中,那么效率更高,因为整个匹配替换循环被提升到C级别:
proc transformFile {sourceFile targetFile RE replacement} {
# Open for reading
set fin [open $sourceFile]
fconfigure $fin -encoding iso8859-1 -translation lf
# Open for writing
set fout [open $targetFile w]
fconfigure $fout -encoding iso8859-1 -translation lf
# Apply the replacement over all lines
regsub -all -line -- $RE [read $fin] $replacement outputlines
puts $fout $outputlines
# All done
close $fin
close $fout
}
最后,正则表达式不一定是进行字符串匹配的最快方法(例如,string match
要快得多,但接受更受限制的模式类型)。将一种替换代码转换为另一种代码并使其快速发展并非百分之百(REs非常灵活)。
答案 1 :(得分:1)
一个100K行的文件并不多(除非每行都是1K字符长:)所以我建议你read
将整个文件放到var中并在那个var上进行替换:
set fd [open file r+]
set buf [read $fd]
set buf [regsub -all $(the-passwd-pattern) $buf ****]
# write it back
seek $fd 0; # This is not safe! See potrzebie's comment for details.
puts -nonewline $fd $buf
close $fd
答案 2 :(得分:1)
特别是对于非常大的文件 - 如上所述 - 它不是将整个文件读入变量的最佳方式。一旦系统内存不足,您就无法阻止应用程序崩溃。对于由换行符分隔的数据,最简单的解决方案是缓冲一行并处理它。
只是举个例子:
# Open old and new file
set old [open "input.txt" r]
set new [open "output.txt" w]
# Configure input channel to provide data separated by line breaks
fconfigure $old -buffering line
# Until the end of the file is reached:
while {[gets $old ln] != -1} {
# Mask sensitive information on variable ln
...
# Write back line to new file
puts $new $ln
}
# Close channels
close $old
close $new
我想不出在Tcl中处理大文件的更好方法 - 请随时告诉我任何更好的解决方案。但是Tcl并不是为了处理大数据文件。对于实际性能,您可以使用编译而不是脚本编程语言。
修改:在while循环中替换![eof $old]
。