删除前两行并向文件添加两行
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
来获取读取的行数,而不是再次迭代它以计算行数。
接下来打开原文件,调用gets
replacement.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)
我有一个以以下内容开头的文本文件:
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
来获取读取的行数,而不是再次迭代它以计算行数。
接下来打开原文件,调用gets
replacement.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)