使用Ruby在文件前添加一行

使用Ruby在文件前添加一行,ruby,file-io,prepend,Ruby,File Io,Prepend,我想用Ruby在文件顶部添加一行,如下所示: # initial file contents something else # file contents after prepending "hello" on its own line hello something else file_prepend("target_file.txt", "hello world!\n") 以下代码仅替换整个文件的内容: f = File.new('myfile', 'w') f.write "test

我想用Ruby在文件顶部添加一行,如下所示:

# initial file contents
something
else

# file contents after prepending "hello" on its own line
hello
something
else
file_prepend("target_file.txt", "hello world!\n")
以下代码仅替换整个文件的内容:

f = File.new('myfile', 'w')
f.write "test string"

没有任何机制可以轻松地完成您想做的事情

相反,您需要打开文件、删除文件、以旧名称打开新文件以进行写入、写入内容,然后根据旧文件的内容写入新文件。这听起来很复杂,但代码很简单:

$ cat prepend.rb 
#!/usr/bin/ruby

File.open("passwd", "r") do |orig|
    File.unlink("passwd")
    File.open("passwd", "w") do |new|
        new.write "test string"
        new.write(orig.read())
    end
end
请注意,我使用的机制不需要检查错误——您可能应该处理每个
文件.open()
请求和
文件.unlink()
请求上的错误——并且它假设文件的全部内容都可以放入内存中。举个简单的例子:

$ rm passwd
$ cp /etc/passwd .
$ ./prepend.rb 
$ head passwd
test stringroot:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
$ 

如果您想处理可能不完全符合内存的文件,则应该对这样的循环类型进行编码(未经测试-最好考虑它是伪代码):


作为替代方案,您可以写入临时文件,如果写入过程成功,则删除该文件并在适当位置重命名该临时文件。无论哪种方法对您最有意义。

fwiw这似乎有效:

#!usr/bin/ruby

f = File.open("myfile", "r+")
lines = f.readlines
f.close

lines = ["something\n"] + lines

output = File.new("myfile", "w")
lines.each { |line| output.write line }
output.close
您可以尝试以下方法:

File.copy_stream(myfile,tempfile)
f = File.open(myfile,'w')
f.write("Hello\n#{File.open(tempfile,'r').read}")
f.close
File.delete(tempfile)

这是一项非常常见的任务:

original_file = './original_file'
new_file = original_file + '.new'
设置测试:

File.open(original_file, 'w') do |fo|
  %w[something else].each { |w| fo.puts w }
end
这是实际代码:

File.open(new_file, 'w') do |fo|
  fo.puts 'hello'
  File.foreach(original_file) do |li|
    fo.puts li
  end
end
将旧文件重命名为安全文件:

File.rename(original_file, original_file + '.old')
File.rename(new_file, original_file)
证明它有效:

puts `cat #{original_file}`
puts '---'
puts `cat #{original_file}.old`
哪些产出:

hello
something
else
---
something
else
您不想尝试将文件完全加载到内存中。这将一直有效,直到你得到一个比你的RAM分配更大的文件,并且机器进入爬行状态,或者更糟,崩溃


相反,要逐行阅读。阅读单个行仍然非常快,并且是可伸缩的。驱动器上必须有足够的空间来存储原始文件和临时文件。

我提出了类似的解决方案,它比我见过的其他解决方案更具描述性,也不那么神秘:

def file_prepend(file, str)
  new_contents = ""
  File.open(file, 'r') do |fd|
    contents = fd.read
    new_contents = str << contents
  end
  # Overwrite file but now with prepended string on it
  File.open(file, 'w') do |fd| 
    fd.write(new_contents)
  end
end

正如一些人所说的,可能不要将其用于较大的文件,但这是一个简单的开始

rd = IO.read 'myfile'
IO.write 'myfile', "hello\n" + rd

在命令行中,可以执行以下操作:

ruby -i -pe '$_= "prepended text\n"+$_ if $. == 1' myfile
或者更有效

ruby -i -pe 'BEGIN { gets; print "prepended text\n" + $_ }; ' myfile
遗憾的是,
-i
(就地)选项并没有真正到位,尽管(而且
sed
s就地选项也没有到位)——在操作之后,我的文件将有一个不同的inode

这让我很难过,因为实际上,如果我没有足够的磁盘空间来存储两个拷贝,我就无法过滤(预编译)一个大文件

不过,在适当的位置进行过滤并不困难(一般来说,过滤并不只是针对第一行)。您需要做的只是:

1) 确保您有单独的读写指针(或用于读写的单独文件对象) 2) 确保已缓冲要重写的未读部分 3) 如果您的筛选操作以较短的文件结束,请在结尾处截断到文件

我在上个月为此编写了包装器类

有了它,你就能做到

Rewriter.new("myfile") do |line, index|
  index == 0 ? "prepended text\n" + line : line
end
或使用可执行文件:

$  i_rewriter 'index == 0 ? "prepended text\n" + line : line' myfile

小心使用(如果中断,可能会损坏文件)。

纯,但有效。最小化与文件相关的操作

`#!/bin/ruby
inv_file = File.open("./1.txt","r+") { |f|
    #Read file string by-string
    until f.eof?
        #Searching for some
        if f.readline[/condition here/]
            #remember position
            offset = f.pos
            #Find it? - stop reading
            break
        end
    end
    #Remember what contains rest of file
    tail = f.readlines
    #Again to offset
    f.pos = offset
    #insert what necessary
    f.puts "INSERTED"
    #reconstruct tail
    f.write tail.join
    }`

小心把文件弄脏。将整个文件读入内存不是一个可扩展的解决方案。我个人喜欢这种简单的修补。对于简单的情况,这是最好的解决方案。回答得很好!可以在整个应用程序中重复使用它。最好的解决方案。谢谢!
`#!/bin/ruby
inv_file = File.open("./1.txt","r+") { |f|
    #Read file string by-string
    until f.eof?
        #Searching for some
        if f.readline[/condition here/]
            #remember position
            offset = f.pos
            #Find it? - stop reading
            break
        end
    end
    #Remember what contains rest of file
    tail = f.readlines
    #Again to offset
    f.pos = offset
    #insert what necessary
    f.puts "INSERTED"
    #reconstruct tail
    f.write tail.join
    }`