【发布时间】:2017-04-02 13:41:30
【问题描述】:
我必须在使用 tcl 脚本时删除文件的最后一行。我知道内容,所以内容替换也可以。但我的内容是必须用空格或换行符替换或必须删除。我的工作陷入了循环。
请让我知道哪种方法最有效,每次循环捕获整个文件内容并替换该字符串更好或只删除最后一行。
请提供一些脚本代码,因为我对 tcl 很陌生。
【问题讨论】:
我必须在使用 tcl 脚本时删除文件的最后一行。我知道内容,所以内容替换也可以。但我的内容是必须用空格或换行符替换或必须删除。我的工作陷入了循环。
请让我知道哪种方法最有效,每次循环捕获整个文件内容并替换该字符串更好或只删除最后一行。
请提供一些脚本代码,因为我对 tcl 很陌生。
【问题讨论】:
我们是在谈论从磁盘上的数据或内存中的数据中删除最后一行吗?这很重要,因为您处理这两种情况的方法完全不同。
您在内存中操作事物的确切方式取决于您是将数据表示为行列表还是大字符串。两种方法都有效。 (我想你也可以做其他事情,但这两种是常见的明显方式。)
如果您将数据作为内存中的行的theLines 的变量中):
set theLines [lreplace $theLines end end]
对于一个特别大的列表,有一些技巧可以提高效率,但归根结底是仔细管理引用:
# Needs a new enough Tcl (8.5 or 8.6 IIRC)
set theLines [lreplace $theLines[set theLines ""] end end]
如果您不知道自己需要它,请尝试第一个版本而不是这个。另请注意,如果您想保留原始行列表,则绝对应该使用第一种方法。
您可能会将内存中的数据作为单个大字符串。在这种情况下,我们可以使用 Tcl 的一些字符串搜索功能来完成这项工作。
set index [string last "\n" $theString end-1]
set theString [string range $theString 0 $index]
上面提到的与lreplace 相关的优化也适用于这里(所有同样的警告):
set index [string last "\n" $theString end-1]
set theString [string range $theString[set theString ""] 0 $index]
在磁盘上工作时,情况有所不同。您需要更加小心,因为您无法轻松撤消更改。有两种通用方法:
将文件读入内存,在那里进行更改(使用上述技术),然后进行(破坏性)普通写出。这是您在进行许多其他更改时需要的方法(例如,从中间删除一行、在中间添加一行、从中间一行添加或删除字符)。
set filename "..."
# Open a file and read its lines into a list
set f [open $filename]
set theLines [split [read $f] "\n"]
close $f
# Transform (you should recognise this from above)
set theLines [lreplace $theLines end end]
# Write the file back out
set f [open $filename "w"]
puts -nonewline $f [join $theLines "\n"]
close $f
找到您不想要的数据作为文件中的偏移量开始的位置,并在该点截断文件。这是处理非常大文件的正确方法,但它相当复杂。
set f [open $filename "r+"]; # NEED the read-write mode!
seek $f -1000 end; # Move to a little bit before the end of the file.
# Unnecessary, and guesswork, but can work and will
# speed things up for a big file very much
# Find the length that we want the file to become. We do this by building a list of
# offsets into the file.
set ptrList {}
while {![eof $f]} {
lappend ptrList [tell $f]
gets $f
}
# The length we want is one step back from the end of the list
set wantedLength [lindex $ptrList end-1]
# Do the truncation!
chan truncate $f $wantedLength
close $f
无论您如何进行磁盘转换,请确保在将其应用于任何真实文件之前对垃圾文件进行测试!特别是,我没有检查过截断方法对末尾没有换行符的文件的作用。它可能有效,但你应该测试一下。
【讨论】: