I’m brand new to ruby, and I’m looking for a way to open a file, read
its content and modify it. I’ve seen that I can open a file in read
write mode, but I can’t figure out how it works. If I want to replace
all occurences of ‘search’ by ‘replace’, for instance, what do I have to
do?
Searching for an answer to this question, I’ve found scripts using gsub!
What is this exclamation mark?
The ! (pronounced bang usually) means that a method is a “dangerous”
version of a method with the same name. In this particular case it
means that it’s the inplace version of gsub (global substitution).
FOLDER = “#{ENV[‘HOME’]}/Desktop/” # or whatever folder you want
INFILE = “input.txt”
OUTFILE = “output.txt”
old = File.read(FOLDER + INFILE) # read file in as one big string
old.gsub!(/\bsearch\b/, “replace”) # do in-place substitution
File.open(FOLDER + OUTFILE, “w”) {|new| new.write(old)} # write
modified text out to disk.
This code does not open “input.txt” in RW mode nor modify it in
place. For one thing, gsub! only works on strings not file objects.
For another, I’m too nervous to do that kind of thing. Of course, if
INFILE == OUTFILE, it would overwrite “input.txt”.
In general, it is a naming convention that a method ending in !
signifies that the method does in-place (destructive) modification to
the receiver. I first ran into this convention when studying scheme
back in the 1980s. I don’t know if has any history beyond that.
Schemers would read gsub! as GEE-SUB-BANG. I’m new to ruby, too, so
I’m not sure if rubyists read it the same way.
The ! (pronounced bang usually) means that a method is a “dangerous”
version of a method with the same name. In this particular case it
means that it’s the inplace version of gsub (global substitution).
OK, thanks for the information and the pronounciation tip.
But I still don’t know how to edit a file while reading it. I’ve made
further googling on the subject, and the only solutions I find are:
“read all, manipulate, write all”, which doesn’t seem very good with
huge files
use -i options with ruby command line, but this seems to work only
with files passed on the command line, which isn’t my case.
So, could somebody tell me if it’s possible to update a file in ruby
(except these two solutions)?
To do in place editing, basically you just do it. The problem is
doing it correctly. One way is to use fixed-size chunks:
CHUNK_SIZE = 1024
File.open(“somefile”, “r+”) do |f|
loop do
pos = f.tell
s = f.read(CHUNK_SIZE)
break if s.nil? # We’ve read and transformed the file
s.gsub!(/a/, ‘b’)
f.seek(pos, IO::SEEK_SET)
f.write(s)
end
end
The problem with this method is if the substitued string is longer or
shorter than the read string it’ll mess it up and you’ll have to
shift the rest of the file around. Another way (and how I believe
ruby’s command line switch -i works) is to write the modified version
to a temporary file, and then remove the original version, replacing
it with the modified version. A third, relatively idiot proof method
is to use the mmap extension. This is awesome, but is not gonna be
portable outside of a *nix. (And introduces another dependency).
I’m brand new to ruby, and I’m looking for a way to open a file, read
its content and modify it. I’ve seen that I can open a file in read
write mode, but I can’t figure out how it works. If I want to replace
all occurences of ‘search’ by ‘replace’, for instance, what do I have to
do?
In general, you need to read in the file (usually line by line) and
write out a new copy with the changes you want. Editing in place is
only possible if the replacement string is exactly the same length as
the original.
Searching for an answer to this question, I’ve found scripts using gsub!
What is this exclamation mark?
It means it changes the object it operates on, rather than returning a
changed copy.
Many thanks all of you! What an incredibly active community ruby has,
I’m impressed. And the tell and seek methods are exactly what I was
looking for (even if I agree the read, manipulate, write is much easier
to write and can address most problems).
Thanks again, and I feel like I’ll soon become a ruby afficionado