如何使用tcl / tk删除文本文件中的第一行

时间:2016-06-27 22:22:35

标签: tcl tk

我可以这样做但是我的方法很笨拙,因为需要打开文件,读取文件,拆分成所有行,重新组合但没有第1行,最后保存文件。

由于这些文本文件可以是大型数据文件,因此要避免(缩短)所有这些处理步骤。也许有人知道更短或更光滑的方式吗?

非常诚挚的谢意!

2 个答案:

答案 0 :(得分:1)

如果你的文件非常大,你实际上必须逐行处理它们,但如果它们只是一个GB左右,你可以通过将内容作为一个块来处理来简化处理数据。

package require fileutil

fileutil::updateInPlace file.ext {apply {data {
    regsub {.*?\n} $data {}
}}}

updateInPlace命令采用文件名和命令前缀。它打开文件,读取内容,并以内容作为参数调用命令前缀:最后,它将文件内容替换为调用的结果。在这种情况下,命令前缀是apply命令和执行工作的匿名函数( lambda )。

编写相同内容的另一种(大多数是等同的)方法是使用命名命令过程:

proc cmd data {
    regsub {.*?\n} $data {}
}

fileutil::updateInPlace file.ext cmd

命令/ lambda的主体可以是删除文本中第一个换行符之前的所有文本的任何内容,例如

    regsub {[^\n]*\n} $data {}

与上面相同(将匹配的文本替换为第一个换行符),但是使用贪婪的匹配

    string range $data [string first \n $data]+1 end

找到第一个换行符的索引并执行后面的所有内容

    join [lrange [split [string trimright $data] \n] 1 end] \n

获取一个行列表并构建一个新文本,其中包含除第一行之外的所有行。

不同的变体并不完全相同。如果文件中没有换行符,则regsubstring range变体不会进行任何更改,但lrange变体会将内容设置为空字符串。

文档:applyfileutil包,joinlrangepackageprocSyntax of Tcl regular expressions,{{ 3}},regsubsplit

答案 1 :(得分:1)

对于一个非常大的文件(在现代机器上,它必须至少500MB才能进入这个类别),你真的你可以做的很多东西可以缩短你正在处理移动大量数据。您移动数据以删除第一行。 (您可以通过截断来删除末尾的行。)

但是你可以做一些能加快速度的技巧。特别是,以兆字节大小的块为单位移动数据要快得多。这样可以充分利用seektell,并以chan truncate结束。

# Open in read-write mode
set f [open $filename r+]
# Read in the stuff we want to delete; reading is easiest way to find end of line
gets $f

##### HOW TO COPY REMAINDER OF FILE TO EARLIER IN FILE #####

set target 0; # Start of file
fconfigure $f -translation binary
set source [tell $f]
while true {
    # Read a megabyte (1024*1024 bytes) from the source position in the file
    seek $f $source
    set data [read $f 1048576]
    set source [tell $f]; # Remember for next iteration
    # If we didn't read anything, we're done.
    if {[string length $data] == 0} {
        break
    }
    # Write the data to the target location in the file. May overlap with where we
    # read from, but won't go past end. (IMPORTANT!)
    seek $f $target
    puts -nonewline $f $data
    set target [tell $f]; # Remember for next iteration
}
# Ensure there's nothing left over at the end
chan truncate $f $target
close $f

正如您所看到的,只需将所有内容读入内存,操作内容然后再将其写出来实际上更容易编码并且更简单的代码,以便失败不会破坏文件。 (你也可以一次流处理一行,写出一个新的临时文件,扩展到非常大,但它需要首先有额外的磁盘空间。)记住,唯一真正容易做的事情到一个大文件是附加到它。

如果可能,最好将非常大的数据集放入数据库中。这是对您的代码进行更广泛的更改。