I am newbie to Ruby so please spare me if the question looks silly. My
question is how to append data at the beginning of a file?
Suppose I have a file named test.rb which contains some text, say
“This is first line
This is second line”
Now if I wanted to append some data at the beginning of the file, lets
say
“This line has to be appended at the beginning of the file”
My program
filename = File.open(“test”,“a”) do |f|
f.puts “This line should appear at the top of each file”;
f.close();
end
is appending at the end of the file. So the output is:
“This is first line
This is second line
This line has to be appended at the beginning of the file”
I searched the forums and found that if I use IO:seek and then try to
append data to the existing file the earlier content which are in the
first lines will get replaced. Is there any easy solution so that I can
get a final output like:
“This line has to be appended at the beginning of the file
This is first line
This is second line”
I am newbie to Ruby so please spare me if the question looks silly. My
question is how to append data at the beginning of a file?
This is not so much a Ruby question, since nearly no operating system
directly
allows appending data to the beginning of a file. The general solution
is to create a new file, putting there the data in the right order,
delete
the old file and rename the new file to the name of the old one.
Renaming a file is done like this:
File.rename(“oldname”,“newname”)
This raises the exception SystemCallError, if renaming fails.
I am newbie to Ruby so please spare me if the question looks silly. My
question is how to append data at the beginning of a file?
This is not so much a Ruby question, since nearly no operating system
directly
allows appending data to the beginning of a file.
Thanks Ronald for your comments. I am wondering may be ruby got some way
around it.
The general solution
is to create a new file, putting there the data in the right order,
delete
the old file and rename the new file to the name of the old one.
Renaming a file is done like this:
File.rename(“oldname”,“newname”)
Yeah I implemented the above mentioned solution and it’s working fine.
The code is
newfile = File.new(“test1”,“w”)
newfile.puts “This line should appear at the top of each file”;
Thanks Ronald for your comments. I am wondering may be ruby
got some way
around it.
It could, but I think it just happens too rare that someone
wants to do this. In more than 2 decades of programming, I
had this need only two or three times, for example.
newfile = File.new(“test1”,“w”)
newfile.puts “This line should appear at the top of each file”;
The difference is that in case of an exception the file is closed
automatically. Otherwise you have to wait for garbage collector. It’s
a good habit to get used to this style.
newfile.puts(File.read(“test”)) will read the entire file into
memory. Don’t do this on large files - use the original way (or even
better, loop over the file with File#read(size)). For small files,
this read() is better.
newfile.puts(File.read(“test”)) will put an extra newline at the
end. Use either
newfile << File.read(“test”)
or
newfile.write(File.read(“test”))
newfile.puts(File.read(“test”)) will read the entire file into
memory. Don’t do this on large files - use the original way (or even
better, loop over the file with File#read(size)). For small files,
this read() is better.
Good point! (Only that prepending data to a file which is so big that
it would be a memory hog, is probably a nightmare anyway.
newfile.puts(File.read(“test”)) will put an extra newline at the
end. Use either
newfile << File.read(“test”)
or
newfile.write(File.read(“test”))
Right, I overlooked this! Thanks for pointing this out.
My solution for this question would be monkey patching the File class:
require ‘tempfile’
class File
def self.prepend(path, string)
Tempfile.open File.basename(path) do |tempfile|
# shift string to tempfile
tempfile << string
File.open(path, 'r+') do |file|
# append original data to tempfile
tempfile << file.read
# reset file positions
file.pos = tempfile.pos = 0
# copy tempfile back to original file
file << tempfile.read
end
end
The code is
File.delete(“test”);
File.rename(“test1”, “test”);
Just a few remarks: better return to your old habit and use the block
form of File.open (btw, you do not need to close the file, File#open
takes care of that when the block is left - even in case of an
exception).
You don’t need to terminate lines with “;”.
Also, you can use variables to make your life easier:
file = “test”
tmp = file + “~”
File.open(tmp, “w”) do |out|
out.puts “This line should appear at the top of each file”
newfile.puts “This line should appear at the top of each file”;
oldfile = File.open(“test”, “r+”)
oldfile.each_line { |line| newfile.puts line}
oldfile.close();
newfile.close();
File.delete(“test”);
File.rename(“test1”, “test”);
that is nice, but it would be ideal if your code is immune to
dependencies (like static filenames, fixed number of files, etc)
eg, consider the *nix cat command, you can easily insert lines at the
beginning or end. In your case eg,
irb(main):006:0> system “ls -la test2.txt”
ls: test2.txt: No such file or directory
=> false
irb(main):007:0> system “cat test.txt”
1
2
3
this
is
a
test=> true
irb(main):008:0> text_insert=“this will be inserted”
=> “this will be inserted”
irb(main):009:0> system “echo #{text_insert} | cat - test.txt”
this will be inserted
1
2
3
this
is
a
test=> true
irb(main):010:0> new_file=“test2.txt”
=> “test2.txt”
irb(main):011:0> system “echo #{text_insert} | cat - test.txt >
#{new_file}”
=> true
irb(main):012:0> system “ls -la test2.txt”
-rw-r–r-- 1 root root 42 Aug 25 09:02 test2.txt
=> true
irb(main):013:0> system “cat test2.txt”
this will be inserted
1
2
3
this
is
a
test=> true
irb(main):014:0>
note that cat is simply flexible. eg,
cat f - g
will concatenate file f, standard input, and file g in that order; thus
inserting standard input bw the contents of files f and g.
i think ARGF is flexible enough. just a simple thought.