删除前两行并向文件添加两行

Delete first two lines and add two lines to file

我有一个以以下内容开头的文本文件:

Title

aaa
bbb
ccc

我不知道该行将包含什么,但我知道文件的结构将是 Title,然后是一个空行,然后是实际的行。我想修改为:

New Title

fff
aaa
bbb
ccc

我想到了this

lineArray = File.readlines(destinationFile).drop(2)
lineArray.insert(0, 'fff\n')
lineArray.insert(0, '\n')
lineArray.insert(0, 'new Title\n')
File.writelines(destinationFile, lineArray)

writelines 不存在。

`writelines' for File:Class (NoMethodError)

有没有办法删除文件的前两行并添加三个新行?

对整个数组使用 put:

File.open("destinationFile", "w+") do |f|
   f.puts(lineArray)
end

我会从这样的事情开始:

NEWLINES = {
  0 => "New Title",
  1 => "\nfff"
}

File.open('test.txt.new', 'w') do |fo|
  File.foreach('test.txt').with_index do |li, ln|
    fo.puts (NEWLINES[ln] || li)
  end
end

这是运行之后test.txt.new的内容:

New Title

fff
aaa
bbb
ccc

想法是在 NEWLINES 散列中提供替换行列表。当从原始文件中读取每一行时,会在散列中检查行号,如果该行存在,则使用相应的值,否则使用原始行。

如果要读取整个文件然后替换,会减少一些代码,但代码会存在可扩展性问题:

NEWLINES = [
  "New Title",
  "",
  "fff"
]

file = File.readlines('test.txt')
File.open('test.txt.new', 'w') do |fo|
  fo.puts NEWLINES
  fo.puts file[(NEWLINES.size - 1) .. -1]
end

它不是很智能,但可以用于简单的替换。

如果您真的想做对,请了解 diff 的工作原理,创建差异文件,然后让它完成繁重的工作,因为它专为此类任务而设计,运行速度极快,并且每天在世界各地的 *nix 系统上使用数百万次。

如果您的文件很大,将它们全部读入内存对性能和内存的影响值得考虑。如果这是一个问题,那么最好的办法是将文件视为流。这是我的做法。

首先,定义您的替换文本:

require "stringio"

replacement = StringOI.new <<END
New Title

fff
END

我已将其设为 StringIO 对象,但如果替换文本在文件中,它也可以是文件对象。

现在,打开目标文件(一个新文件)并将替换文本中的每一行写入其中。

dest = File.open(dest_fn, 'wb') do |dest|
replacement.each_line {|ln| dest << ln }

我们本可以更有效地做到这一点,但这样做有充分的理由:现在我们可以调用 replacement.lineno 来获取读取的行数,而不是再次迭代它以计算行数。

接下来打开原文件,调用getsreplacement.lineno次向前查找:

orig = File.open(orig_fn, 'r')
replacement.lineno.times { orig.gets }

最后,将原文件的剩余行写入新文件。这次我们会用 File.copy_stream:

更有效地做到这一点
File.copy_stream(orig, dest)
orig.close
dest.close

就是这样。当然,手动关闭这些文件是一种拖拽(而且我们应该在 ensure 块中进行),所以最好使用 File.open 的块形式来自动关闭它们。此外,我们可以将 orig.gets 调用移动到 replacement.each_line 循环中:

File.open(dest_fn, 'wb') do |dest|
  File.open(orig_fn, 'r') do |orig|
    replacement.each_line {|ln| dest << ln; orig.gets }
    File.copy_stream(orig, dest)
  end
end

首先创建一个输入测试文件。

FNameIn = "test_in"

text = <<_
Title

How now,
brown cow?
_
  #=> "Title\n\nHow now,\nbrown cow?\n" 

File.write(FNameIn, text)
  #=> 27

现在逐行读写。

FNameOut = "test_out"

File.open(FNameIn) do |fin|
  fin.gets; fin.gets  
  File.open(FNameOut, 'w') do |fout|
    fout.puts "New Title"
    fout.puts
    fout.puts "fff"
    until fin.eof?    
      fout.puts fin.gets
    end
  end
end

查看结果:

puts File.read(FNameOut)
  # New Title
  #
  # fff
  # How now,
  # brown cow?

Ruby 将在块终止时关闭两个文件中的每一个。

如果文件不大,你可以这样写:

File.write(FNameOut,
  ["New Title\n", "\n", "fff\n"].concat(File.readlines(FNameIn).drop(2)).join)