如何编写一个tcl脚本来删除文件的最后一行

时间:2017-03-31 15:36:25

标签: file tcl

我必须使用tcl脚本删除最后一行文件。我知道内容,所以内容替换也没关系。但我的内容必须由空格或换行符替换或必须删除。我的工作是循环的。

请让我知道哪种方法有效,每次循环捕获整个文件内容并更换该字符串更好或只删除最后一行。

请提供一些脚本代码,因为我对tcl很新。

1 个答案:

答案 0 :(得分:1)

我们是否正在讨论从磁盘上的数据或内存中的数据中删除最后一行?这很重要,因为你用来做这两种情况的方法是完全不同的。

在内存中

你在内存中操作事物的确切方式取决于你是将数据表示为行列表还是大字符串。两种方法都有效。 (我想你也可以做其他事情,但这两种是常见的明显方式。)

  1. 如果你的数据是内存中的行,你可以简单地做(假设你把这些行放在一个名为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]
    

    如果您不知道需要,请尝试使用第一个版本而不是此版本。另外要注意,如果你想保留原来的行列表,你一定要使用第一种方法。

  2. 您可能会将内存中的数据作为单个大字符串。在这种情况下,我们可以使用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]
    
  3. 在磁盘上

    在磁盘上工作时,情况有所不同。您需要更加小心,因为您无法轻松撤消更改。有两种通用方法:

    1. 将文件读入内存,在那里进行更改(使用上述技术),并进行(破坏性)普通写入。这是您在进行许多其他更改时所需的方法(例如,从中间删除一条线,向中间添加一条线,在中间添加或删除一行中的字符)。

      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
      
    2. 找到您不想要的数据作为文件中的偏移量开始并在此时截断文件。这是一个非常大的文件的正确方法,但它更复杂。

      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
      
    3. 然而,您执行磁盘转换,确保您在垃圾文件上进行测试,然后再应用于任何真实的内容!特别是,我没有检查截断方法对文件的影响,最后没有换行符。 可能有效,但你应该测试。