写入固定宽度文件的最有效方法(Ruby)

时间:2010-05-12 13:36:01

标签: ruby file performance

我目前正在使用极大的固定宽度文件,有时超过一百万行。我编写了一个可以根据一组参数写入文件的方法,但我认为必须有一种更有效的方法来实现这一点。我正在使用的当前代码是:

def self.writefiles(file_name, positions, update_value)
@file_name = file_name
@positions = positions.to_i
@update_value = update_value

line_number = 0
@file_contents = File.open(@file_name, 'r').readlines

    while line_number < @file_contents.length
       @read_file_contents = @file_contents[line_number]
       @read_file_contents[@positions] = @update_value
       @file_contents[line_number] = @read_file_contents
       line_number += 1
    end

write_over_file = File.new(@file_name, 'w')
line_number = 0 

    while line_number < @file_contents.length
        write_over_file.write @file_contents[line_number]
        line_number += 1
    end

write_over_file.close
end

例如,如果文件中的位置25表明它是原始文件,则该值将设置为“O”,如果我想替换该值,我将使用ClassName.writefiles(filename,140,“X” )改变每一行的这个位置。任何有助于提高此方法效率的帮助都将非常感激!

由于

3 个答案:

答案 0 :(得分:1)

如果它是固定宽度的文件,您可以打开文件进行读/写,并使用搜索移动到要写入的数据的开头,并且只写入您正在更改的数据而不是整行。这可能比重写整个文件以替换一个字段更有效。

这是一个粗略的例子。它读取最后一个字段(10,20,30),将其递增1,并将其写回:

tha_file (每行10个字符,包括换行符)

12 3 x 10
23 4 x 20
78 9 x 30

<强> seeker.rb

#!/usr/bin/env ruby
fh=open("tha_file", "r+")

$RECORD_WIDTH=10
$POS=8
$FIELD_WIDTH=2

# seek to first field
fh.seek($POS - 1, IO::SEEK_CUR)

while !fh.eof?

  cur_val=fh.read($FIELD_WIDTH).to_i
  puts "read #{cur_val}"
  fh.seek(-1 * $FIELD_WIDTH, IO::SEEK_CUR)
  cur_val = cur_val + 1

  fh.write(cur_val)
  puts "wrote #{cur_val}"

  # Move to start of next field in the middle of next record
  fh.seek($RECORD_WIDTH - $FIELD_WIDTH, IO::SEEK_CUR)
end

答案 1 :(得分:0)

#!/usr/bin/ruby
# replace_at_pos.rb
pos, char, infile, outfile = $*
pos = pos.to_i
File.open(outfile, 'w') do |f|
  File.foreach(infile) do |line|
    line[pos] = char
    f.puts line
  end
end

并将其用作:

replace_at_pos.rb 140 X inputfile.txt outputfile.txt

要替换值集,可以使用哈希:

replace = {
  100 => 'a',
  155 => 'c',
  151 => 't'
}
. . .
replace.each do |k, v|
  line[k] = v
end

答案 2 :(得分:0)

通过重新编写程序一次读取一行文件(当前正在将整个文件读入内存),您肯定会节省一些时间和相当多的内存。然后,您可以在循环中写入文件的备份副本,然后在末尾重命名该文件。这样的事情。

  def self.writefiles2(file_name, positions, update_value)
    @file_name = file_name
    @new_file = file_name + ".bak"
    @positions = positions.to_i
    @update_value = update_value

    line_number = 0
    reader = File.open(@file_name, 'r')
    writer = File.open(@new_file, 'w')

    while (line = reader.gets() and not line.nil? )
      line[@positions] = @update_value
      writer.puts(line)
    end
    reader.close
    writer.close
    # Rename the file
  end

这当然需要在重命名元素周围进行一些错误处理,这可能会导致输入数据丢失。