Luminusss
Luminusss

Reputation: 571

Changing information in a CSV file

I'm trying to write a ruby script that will read through a CSV file and prepend information to certain cells (for instance adding a path to a file). I am able to open and mutate the text just fine, but am having issues writing back to the CSV without overriding everything. This is a sample of what I have so far:

CSV.foreach(path) { |row|
    text = row[0].to_s
    new_text = "test:#{text}"
}

I would like to add something within that block that would then write new_textback to the same reference cell(row) in the file. The only way I have to found to write to a file is

 CSV.open(path, "wb") { |row|
     row << new_text
 }

But I think that is bad practice since you are reopening the file within the file block already. Is there a better way I could do this?

EX: I have a CSV file that looks something like:

file,destination
test.txt,A101

and need it to be:

file,destination
path/test.txt,id:A101

Hope that makes sense. Thanks in advance!

Upvotes: 0

Views: 85

Answers (2)

chrisdurheim
chrisdurheim

Reputation: 426

Depending on the size if the file, you might consider loading the contents of the file into a local variable and then manipulating that, overwriting the original file.

lines = CSV.read(path)

File.open(path, "wb") do |file|
  lines.each do |line|
    text = line[0].to_s
    line[0] = "test:#{text}" # Replace this with your editing logic
    file.write CSV.generate_line(line)
  end
end

Alternately, if the file is big, you could write each modified line to a new file along the way and then replace the old file with the new one at the end.

Upvotes: 1

pjs
pjs

Reputation: 19855

Given that you don't appear to be doing anything that draws on CSV capabilities, I'd recommend using Ruby's "in-place" option variable $-i.

Some of the stats software I use wants just the data, and can't deal with a header line. Here's a script I wrote a while back to (appear to) strip the first line out of one or more data files specified on the command-line.

#! /usr/bin/env ruby -w
#
# User supplies the name of one or more files to be "stripped"
# on the command-line.
#
# This script ignores the first line of each file.
# Subsequent lines of the file are copied to the new version.
#
# The operation saves each original input file with a suffix of
# ".orig" and then operates in-place on the specified files.

$-i = ".orig"   # specify backup suffix

oldfilename = ""

ARGF.each do |line|
  if ARGF.filename == oldfilename   # If it's an old file
    puts line                       # copy lines through.
  else                              # If it's a new file remember it
    oldfilename = ARGF.filename     # but don't copy the first line.
  end
end

Obviously you'd want to change the puts line pass-through to whatever edit operations you want to perform.

I like this solution because even if you screw it up, you've preserved your original file as its original name with .orig (or whatever suffix you choose) appended.

Upvotes: 0

Related Questions