Ruby: Append text to the 2nd line of a file
You write a new file, applying your change at the desired line, then rename result back to the original file name. The following method will copy the file and yield the output file object to a block at the correct line, so that block can output your new lines.
def insert_lines_following_line file, line_no
tmp_fn = "#{file}.tmp"
File.open( tmp_fn, 'w' ) do |outf|
line_ct = 0
IO.foreach(file) do |line|
outf.print line
yield(outf) if line_no == (line_ct += 1)
end
end
File.rename tmp_fn, file
end
insert_lines_following_line( "#{curDir}/Backup_Times.csv", 1 ) do |outf|
# output new csv lines in this block
outf.puts ['foo','bar','baz',1,2,3].join(",") # or however you build your csv line
end
How to insert a line in the middle of a text file?
Think of file as a piece of paper. Once you've written something on it, the only safe way to add content is to append. You can't write text in the middle of the paper without overwriting something.
Generally, this kind of insertion is done via a temporary file. It goes like this:
- Open source file
source
for reading - Create a new file
target
for writing - Read from
source
up to the point of insertion and write that totarget
- Write your new content to
target
- Copy the rest of
source
totarget
- Close the files
- Delete/rename
source
- Rename
target
to whatsource
was named.
Append line every n lines to file - ruby
Here are a couple options.
Option 1:
File.open('output.txt', 'w') do |outfile|
File.foreach('input.txt').each_with_index do |line, i|
outfile.puts(line)
outfile.puts '--- 1000 ---' if (i + 1) % 1000 == 0 && i != 0
end
end
This inserts the line '--- 1000 ---'
after every 1000 lines from the original file. It has some drawbacks though. Mainly it has to check each index and check that we are not at line zero with every line! But it works. And it works on large files without hogging memory.
Option 2:
File.open('output.txt', 'w') do |outfile|
File.foreach('input.txt').each_slice(1000) do |lines|
outfile.puts(lines)
outfile.puts '--- 1000 ---'
end
end
This code does almost exactly the same thing using Enumerable
's each_slice
method. It yields an array of every 1000 lines, writes them out using puts
(which accepts Array
s), then writes our marker line after it. It then repeats for the next 1000 lines. The difference is if the file isn't a multiple of 1000 lines the last call to this block will yield an array smaller than 1000 lines and our code will still append our line of text after it.
We can fix this by testing the array's length and only writing out our line if the array is exactly 1000 lines. Which will be true for every batch of 1000 lines except the last one (given a file that is not a multiple of 1000 lines).
Option 2a:
File.open('output.txt', 'w') do |outfile|
File.foreach('input.txt').each_slice(1000) do |lines|
outfile.puts(lines)
outfile.puts '--- 1000 ---' unless lines.size < 1000
end
end
This extra check is only needed if appending that line to the end of the file is a problem for you. Otherwise you can leave it out for a small performance boost.
Speaking of performance, here is how each option performed on a 335.5 MB file containing 1,000,000 paragraphs of Lorem Ipsum. Each benchmark is total time to process the entire file 100 times.
Option 1:
103.859825 44.646519 148.506344 (152.286349)
[Finished in 152.6s]
Option 2:
96.249542 43.780160 140.029702 (145.210728)
[Finished in 145.7s]
Option 2a:
98.041073 45.788944 143.830017 (149.769698)
[Finished in 150.2s]
As you can see, option 2 is the fastest. Keep in mind, options 2/2a will in theory use more memory since it loads 1000 lines at a time, but even then it's capped at a very small level so handling enormous files shouldn't be a problem. However they are all so close I would recommend going with whatever option reads the best or makes the most sense.
Hope this helped.
How to append a text to file succinctly
Yes. It's poorly documented, but you can use:
File.write('foo.txt', 'some text', mode: 'a+')
Delete first two lines and add two lines to file
I'd start with something like this:
NEWLINES = {
0 => "New Title",
1 => "\nfff"
}
File.open('test.txt.new', 'w') do |fo|
File.foreach('test.txt').with_index do |li, ln|
fo.puts (NEWLINES[ln] || li)
end
end
Here's the contents of test.txt.new
after running:
New Title
fff
aaa
bbb
ccc
The idea is to provide a list of replacement lines in the NEWLINES
hash. As each line is read from the original file the line number is checked in the hash, and if the line exists then the corresponding value is used, otherwise the original line is used.
If you want to read the entire file then substitute, it reduces the code a little, but the code will have scalability issues:
NEWLINES = [
"New Title",
"",
"fff"
]
file = File.readlines('test.txt')
File.open('test.txt.new', 'w') do |fo|
fo.puts NEWLINES
fo.puts file[(NEWLINES.size - 1) .. -1]
end
It's not very smart but it'll work for simple replacements.
If you really want to do it right, learn how diff
works, create a diff file, then let it do the heavy lifting, as it's designed for this sort of task, runs extremely fast, and is used millions of times every day on *nix systems around the world.
How to append a new line write to a file with ruby?
try this
def write_to_file(line, my_file)
File.open(my_file, 'a') do |file|
p '-----loop number:' + line.to_s
file.puts "#{line}"
end
end
[1,2,3,4].each do |line|
write_to_file(line, my_file)
end
Add a new line in file?
Use IO#puts.
file.puts @string
How to add new line in a file
Reading and writing a file at the same time can get messy, same thing with other data structures like arrays. You should build a new file as you go along.
Some notes:
- you should use the block form of
File.open
because it will stop you from forgetting to callf.close
puts nil
is the same asputs
without arguments- single quotes are preferred over double quotes when you don’t need string interpolation
- you should use
do ... end
instead of{ ... }
for multi-line blocks File.open(...).each
can be replaced withFile.foreach
- the intermediate result can be stored in a
StringIO
object which will respond toputs
etc.
Example:
require 'stringio'
file = 'test.txt'
output = StringIO.new
File.foreach(file) do |line|
if line.include? '2014-10'
output.puts
else
output << line
end
end
output.rewind
File.open(file, 'w') do |f|
f.write output.read
end
How do I add a line after another line in a file, in Ruby?
Assuming you want to do this with the FileEdit class.
Chef::Util::FileEdit.new('/path/to/file').insert_line_after_match(/three/, 'four')
Related Topics
Hook Before All Delyed Job Success Callback to Save Successfully Completed Jobs
How to Sign Out in a Rails App, Using Devise Gem, No Route Matches /Users/Sign_Out
Ruby: How to Remove Items from Array a If It's Not in Array B
Use Some Middleware Only for Specific Rack Website
Delete from Database with Specific Details in Ruby
Make Map Marker Direct Link Onclick for Gmaps4Rails
Method Gives Activerecord::Relation Error
If Statement in Ruby Using Regex
Pass Ruby Script File to Rails Console
How to Add 'Each' Method to Ruby Object (Or Should I Extend Array)
How to Return the Number of Devise Users Currently Logged In
How to Mimic Browser X509 Client Certificate Verification Without Access to Http Layer
How to Make Private Activities
How to Add "Access-Control-Allow-Origin" Headers to API Response in Ruby
Receving the Undefined Method 'Generators' Error
Rails 3 - Devise/Actionmailer/Ruby-Smtp Causing a Segmentation Fault