在ruby中,如何重命名文本文件,保留相同的句柄并删除旧文件

时间:2015-03-24 15:38:31

标签: ruby handle delete-file

我使用常量(FLOG)作为写入日志的句柄。在给定的点上,我必须使用临时日志,然后将该内容附加到常规日志中,所有具有相同句柄的内容通过一堆方法使用。
我的测试程序如下。关闭手柄后,FLOG'与临时日志相关联,当我将FLOG重新分配给新日志时,这会以某种方式重新打开临时日志,而我无法删除它。 有没有办法确保旧的临时文件保持接近(所以我可以删除它)

# Pre-existing log:
final_log = "final_#{Time.now.strftime("%Y%m%d")}.txt"

#Writing something in it
File.open(final_log, "w+") { |file| file.write("This is the final log: #{final_log}\n") }

# temp log:
temp_log = "temp_#{Time.now.strftime("%Y%m%d")}.txt"
FLOG = File.new(temp_log, "w+")

# write some stuff in temp_log
FLOG.puts "Writing in temp_log named #{temp_log}"

# closing handle for temp_log
FLOG.close  

# avoid constant reuse warning:
Object.send(:remove_const,'FLOG') if Object.const_defined?('FLOG')

# need to append temp_log content to final_log with handle FLOG 
FLOG = File.open(final_log, "a+") 

# appending old temp log to new log 
File.open(temp_log, "r").readlines.each do |line|
    puts "appending...  #{line}"
    FLOG.puts "appending...  #{line}"               
end

# closing handle    
FLOG.close

# this tells me that 'temp_log' is somehow re-opened:
ObjectSpace.each_object(File) { |f| puts("3: #{temp_log} is open") if f.path == temp_log && !f.closed? }

File.delete(temp_log)       # Cant do that:
# test_file2.rb:35:in `delete': Permission denied - temp_20150324.txt (Errno::EACCES)

2 个答案:

答案 0 :(得分:0)

如果您要使用临时文件,请使用tempfile

require 'tempfile'

# Pre-existing log:
final_log = "final_#{Time.now.strftime("%Y%m%d")}.txt"

#Writing something in it
File.open(final_log, "w+") { |file| file.write("This is the final log: #{final_log}\n") }

# give the tempfile a meaningful prefix
temp_log = Tempfile.new('foobar')
begin
  $flog = temp_log

  # write some stuff in temp_log
  $flog.puts "Writing in temp_log named #{temp_log.path}"

  # need to append temp_log content to final_log with handle $flog
  $flog = File.open(final_log, "a+")

  # reopen temp_log for reading, append to new log
  temp_log.open.readlines.each do |line|
    puts "appending...  #{line}"
      $flog.puts "appending...  #{line}"
  end

  # closing handle
  $flog.close
ensure
  # delete temp_log
  temp_log.unlink
end

虽然全局变量一般都很糟糕,但是一个常量变化很大,所以你可以像全局一样使用它更糟糕。

答案 1 :(得分:0)

temp_log仍未打开,因为您没有关闭它。如果你做了类似的事情:

temp_log_lines = File.open(temp_log, 'r') { |f| f.readlines }

然后在块结束时关闭temp_log的I / O流。但是,执行File.open(temp_log, "r").readlines会获取IO返回的File.open对象,并在其上调用readlines,然后使用随附的块调用each。由于该块是您调用each而不是File.open的一部分,因此该流不会在其结束时关闭,并且对于该程序的其余部分保持打开状态。

至于为什么你不能在程序结束时删除temp_log,很难说不知道底层文件系统中发生了什么。如果你删除一个你打开了一个流但没有关闭的文件,那么Ruby和底层(POSIX)操作系统都不会抱怨;该文件将被取消链接,但流将保持不变并仍然具有该文件的内容,依此类推。您得到的错误是该程序的Ruby进程的所有者无权删除程序创建的文件。这很奇怪,但很难从这段代码中诊断出来。考虑程序正在使用的目录,对它的权限是什么等等。

更一般地说,你可以在Ruby中使用一些可以让你的生活更轻松的东西。

如果你想要一个临时文件,你可以使用一个Tempfile课程,为你做很多工作。

在Ruby中使用文件进行I / O的惯用方法是将块传递给File.open。该块被传递给文件的I / O流,该文件在块结束时自动关闭,因此您无需手动执行此操作。这是一个例子:

flog = File.new(temp_log, 'w+') do |f|
  f.puts "Writing in temp_log named #{temp_log}"
end

FLOG不是代码中的真正常量。 A constant is only a constant if its value never changes throughout the life of the program it's declared in. Ruby是一种非常宽松的语言,所以它允许你重新分配它们,但是如果你这样做就警告你。如果你这样做,更严格的语言会引发错误。 FLOG只是一个普通变量,应该写成flog。很好地使用常量是程序操作外部的一个值,程序需要能够引用它 - 例如,每次需要引用pi的近似值时,不要写3.141592653589793,你可以声明PI = 3.141592653589793并在之后使用PI。在Ruby中,这已在Math模块中为您完成 - Math::PI返回此信息。用户设置是常量常常显示的另一个地方 - 它们在程序开始之前确定,帮助确定它的作用,并且在执行期间应该不加修改,因此将它们存储在常量中有时是有意义的。

您描述了作为测试程序提供的程序。 Ruby拥有非常好的测试库,你可以使用它比编写这样的脚本更好。 Minitest是Ruby标准库的一部分,是我在Ruby中最喜欢的测试框架,但很多人也喜欢RSpec。 (我想链接到这些框架的文档,但我没有足够的声誉 - 抱歉。你必须要谷歌。)

如果你像这样强制编写你的代码,那么很难利用这些框架。 Ruby是一种非常面向对象的语言,在使用它时,您将以面向对象的方式构建代码。如果您对OO设计不熟悉,那些对我来说非常有用的书籍是Sandi Metz的 Ruby中的实用面向对象设计重构:改进现有代码的设计< / Martin>由Martin Fowler等人和不断增长的面向对象软件,由测试指导,由Steve Freeman和Nat Pryce完成。 (这里缺少链接也一样。)