ruby读取和写入/更改同一文件

ruby读取和写入/更改同一文件,ruby,Ruby,我正在尝试更改现有文件的内容。我有这段代码,它是有效的。但我想找到一种更好的方法,在打开文件的一次操作中进行操作 File.open(file_name , 'r') do |f| content = f.read end File.open(file_name , 'w') do |f| content.insert(0, "something ") f.write(content) end 有没有办法只打开一次文件 我尝试过使用File.open(文

我正在尝试更改现有文件的内容。我有这段代码,它是有效的。但我想找到一种更好的方法,在打开文件的一次操作中进行操作

  File.open(file_name , 'r') do |f|
    content = f.read
  end
  File.open(file_name , 'w') do |f|
    content.insert(0, "something ")
    f.write(content)
  end
有没有办法只打开一次文件


我尝试过使用
File.open(文件名为'r+')
,它似乎只附加到文件的末尾(无法在文件的开头插入内容)。

您可以在同一个文件中执行此操作,但可能会覆盖文件的内容

每个文件操作都会将文件的光标设置到不同的位置,这是后一个操作所使用的位置。所以,如果你读了8个字节,你必须提前8个字节返回光标,并且只写8个字节来不覆盖任何内容,如果你写的字节更少,你将保持不变的字节

Ruby文件类是IO类,在中有文档记录


要打开文件进行读/写操作,请使用“r+”模式。

看起来您希望
IO::SEEK_SET
使用
0
在读取后倒带文件指针

file_name = "File.txt";

File.open(file_name , 'r+') do |f|
    content = f.read
    content.insert(0, "somehting else")
    f.seek(0, IO::SEEK_SET)
    f.write(content)
end

[编辑:我误解了你的问题,但我下面的代码只需插入一行即可修复:

text_to_prepend = ''
之后

它可以简化一点(针对您的问题),但我将保持原样,以显示如何在每一行前面添加相同的字符串。]

您可以只打开一次文件,并且在写入之前不读取整个文件,但这很混乱,而且有点棘手。基本上,您需要在读取和写入之间移动文件指针,并维护一个缓冲区,该缓冲区包含文件中的行,当写入每个修改的行时,这些行将被全部或部分覆盖

在每个步骤中,从缓冲区中删除第一行并修改它以准备写入。但是,在写入之前,您可能需要将一个或多个附加行读入缓冲区,以便在写入修改后的行后,读取指针保持在写入指针之前。读取所有行后,修改并写入缓冲区中的每一行

代码

def prepend_file_lines(file_name, text_to_prepend)
  f = File.open(file_name, 'r+')
  return if f.eof?
  write_pos = 0
  line_in = f.readline
  read_pos = line_in.size
  buf = [line_in]
  last_line_read = f.eof?
  loop do
    break if buf.empty?   
    line_out = text_to_prepend + buf.shift
    while (!last_line_read && read_pos <= write_pos + line_out.size) do
      line_in = f.readline 
      buf << line_in 
      read_pos += line_in.size
      last_line_read = f.eof?
    end
    f.seek(write_pos, IO::SEEK_SET) 
    write_pos += f.write(line_out)
    f.seek(read_pos, IO::SEEK_SET) 
  end
end
现在让我们试试:

prepend_file_lines("sample.txt", "Here's to Matz: ")

File.readlines(F_NAME).each { |l| puts l } 
  # Here's to Matz: Now is
  # Here's to Matz: the time
  # Here's to Matz: for all Rubiests
  # Here's to Matz: to raise their
  # Here's to Matz: glasses to Matz.

请注意,在测试时,有必要在每次调用
prepend_file_line
之前写入测试文件,因为文件正在被修改。

可以。如果不打开文件两次,我们怎么做?@dli只是使用“r+”模式。虽然这个问题乍一看并不是重复的,但我相信它问的问题与您的基本相同:如果文件非常大,这可能不是最好的主意-将整个原始文件读入内存不会有意思。@JKillian,这是非常正确的,但是由于OP提到他当前的解决方案已经开始工作,并且我没有改变内存要求,他没有处理足够大的文件来遇到这个问题。同意,小文件不应该是一个问题。只是为了将来读者的利益想提一下
text =<<_
Now is
the time
for all Rubiests
to raise their
glasses to Matz.
_

F_NAME = "sample.txt"
File.write(F_NAME, text)
File.readlines(F_NAME).each { |l| puts l } 
  # Now is
  # the time
  # for all Rubiests
  # to raise their
  # glasses to Matz.
prepend_file_lines("sample.txt", "Here's to Matz: ")

File.readlines(F_NAME).each { |l| puts l } 
  # Here's to Matz: Now is
  # Here's to Matz: the time
  # Here's to Matz: for all Rubiests
  # Here's to Matz: to raise their
  # Here's to Matz: glasses to Matz.