逐行编辑CSV文件

时间:2014-05-31 09:26:51

标签: ruby csv

我有一个包含两列数字的长CSV文件:

1,2
2,5
7,3
etc...

我想添加第三列,等于前两位的总和:

1,2,3
2,5,7
7,3,10

以下代码是问题的解决方案,它会复制输入文件,并附加第三列。相反,我想逐行操作输入文件,在我进行时将第三列写入每一行。如果进程因某种原因出错,则应该已经保存了文件前半部分的答案,不需要重新计算。

我无法使用ruby的CSV课程来提供一个很好的方法。这是我目前使用复制文件的解决方案:

require 'csv'

CSV.open("big_file.csv", "w") do |csv|
  csv << %w{1 2}
  csv << %w{2 5}
  csv << %w{3 8}
end

big_csv_file = CSV.open("big_file.csv", 'r')


# I'm creating a copy of big_file.csv here
# I'd rather edit it in place

CSV.open("copy_with_extra_column.csv", "w") do |csv|
  big_csv_file.each do |row|
    row << eval(row[0] + row[1])
    csv << row
  end
end

3 个答案:

答案 0 :(得分:1)

文件就像一个长字符串,例如:

1,2\n2,5

但是,与字符串不同,您只能覆盖文件中的字符。在上面的示例中,有7个字符。您可以使用您选择的任何字符覆盖任何这些字符。因此,例如,如果您将数字之和放在位置0和位置2到位置3,结果是:

1,232,5

这可能不是你想要的,因为看起来前两个数字分别是1和232,它们的总和是5.但是,这就是你在地方编辑文件时所能做的:你只能覆盖字符与其他角色。

对于大文件,您可以读取一行,然后将更改的行写入新文件。完成后,您可以删除原始文件,然后可以将新文件重命名为旧文件名。您可以使用Tempfile类来避免新文件名的名称冲突。

答案 1 :(得分:1)

换句话说,在基本文件级别,没有办法将总和“插入”到文件中。在您的示例中:

1,2
2,5
7,2

如果我们忽略“CSV”文件的整个概念(实际上只是在流文本文件之上分层的概念)要在第一行的末尾“插入”文本,3,我们需要做所有这些事情:

  1. 移动2之后的“\ n”,以及后面的所有文本在文件后面的两个位置(留下一些垃圾)
  2. 用“,3”
  3. 覆盖垃圾

    然后,您将为每个额外的行重复此过程。

    这显然效率很低。简单来说,CSV文件格式不是为有效插入数据而设计的。

    您的两个选择是:

    1. 将文件加载到内存中(例如,行数组),在那里对其进行操作,然后将其全部写回到现有文件上。假设您的文件只会增长,这样可以正常工作,但您需要愿意分配足够的内存来读取和操作整个文件。
    2. 在处理数据时写入临时文件,然后在完成后移动临时文件代替原始文件。
    3. “就地”更新文件是不切实际的。

答案 2 :(得分:0)

而不是CSV.open(),请尝试CSV.read()。例如,它显然有点难看,但是:

big_csv_file = CSV.read("big_file.csv")

big_csv_file[0] << eval(big_csv_file[0][0] + big_csv_file[0][1])

CSV.open("copy_with_extra_column.csv", "w") do |csv|
  big_csv_file.each do |row|
    csv << row
  end
end

如果你需要文件始终是最新的,那么显然需要改变和写作。