can you create / write / append a string to a file in a single line in Ruby
Ruby has had IO::write
since 1.9.3. Your edit shows you're passing the wrong args. The first arg is a filename, the second the string to write, the third is an optional offset, and the fourth is a hash that can contain options to pass to the open. Since you want to append, you'll need to pass the offset as the current size of the file to use this method:
File.write('some-file.txt', 'here is some text', File.size('some-file.txt'), mode: 'a')
Hoisting from the discussion thread:
This method has concurrency issues for append because the calculation of the offset is inherently racy. This code will first find the size is X, open the file, seek to X and write. If another process or thread writes to the end between the File.size
and the seek/write inside File::write
, we will no longer be appending and will be overwriting data.
If one opens the file using the 'a' mode and does not seek, one is guaranteed to write to the end from the POSIX semantics defined for fopen(3) with O_APPEND
; so I recommend this instead:
File.open('some-file.txt', 'a') { |f| f.write('here is some text') }
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+')
Prepend a single line to file with Ruby
This is a pretty common task:
original_file = './original_file'
new_file = original_file + '.new'
Set up the test:
File.open(original_file, 'w') do |fo|
%w[something else].each { |w| fo.puts w }
end
This is the actual code:
File.open(new_file, 'w') do |fo|
fo.puts 'hello'
File.foreach(original_file) do |li|
fo.puts li
end
end
Rename the old file to something safe:
File.rename(original_file, original_file + '.old')
File.rename(new_file, original_file)
Show that it works:
puts `cat #{original_file}`
puts '---'
puts `cat #{original_file}.old`
Which outputs:
hello
something
else
---
something
else
You don't want to try to load the file completely into memory. That'll work until you get a file that is bigger than your RAM allocation, and the machine goes to a crawl, or worse, crashes.
Instead, read it line by line. Reading individual lines is still extremely fast, and is scalable. You'll have to have enough room on your drive to store the original and the temporary file.
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 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.
How to insert a string into a textfile
If it's a small file I think the easiest way would be to:
- Read the complete file.
- Insert the line.
- Write the new file.
That is the way Rails does it behind the scenes.
Or you can copy it line by line and then overwrite the original with mv
like this:
require 'fileutils'
tempfile=File.open("file.tmp", 'w')
f=File.new("file.txt")
f.each do |line|
tempfile<<line
if line.downcase=~/^line2/
tempfile << "Some nice little sentence\n"
end
end
f.close
tempfile.close
FileUtils.mv("file.tmp", "file.txt")
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
Add each array element to the lines of a file in ruby
Either use Array#each
to iterate over your array and call IO#puts
to write each element to the file (puts
adds a record separator, typically a newline character):
File.open("test.txt", "w+") do |f|
a.each { |element| f.puts(element) }
end
Or pass the whole array to puts
:
File.open("test.txt", "w+") do |f|
f.puts(a)
end
From the documentation:
If called with an array argument, writes each element on a new line.
Related Topics
Fastest Way to Find a String into an Array of String
How to Properly Test Cancan Abilities with Rspec
Raise Exception on Shell Command Failure
How to Make a Method Available to Both My Controller and Model in Rails
Rvm with Jruby 1.7.0 "Unknown Ruby Interpreter"
How to Create Pretty JSON in Chef (Ruby)
Hash Remove All Except Specific Keys
Undefined Method When Accessing Hash Element
Is There a Definitive Reference Document for Ruby Syntax
Installing Pl/Ruby for Postgresql 8.3
Why Does Psych Yaml Interpreter Add Line Breaks Around 80 Characters
Accessing Headers from Sinatra
Sinatra + Heroku + Datamapper Deploy Issues with Dm-Sqlite-Adapter
How to Refer a Local Gem in Ruby