Force the file opened with "r+" to end - ruby

There is a file with some marker word in it:
qwerty
I am the marker!
zxcvbn
123456
I want to overwrite all the rest of the file after the marker with some unknown amount of lines instead:
qwerty
I am the marker!
inserted line #1
inserted line #2
inserted line #3
But if there are too few lines to be inserted, the tail can be still there, that I do not need:
qwerty
I am the marker!
inserted line #1
123456
Here is my code (simplified):
File.open("file.txt", "r+") do |file|
file.gets "marker"
file.gets
lines_to_insert.each do |line|
file.puts line
end
# I wish I could do file.put_EOF here
end

File.open("file.txt", "r+") do |file|
file.gets "marker"
file.gets
lines_to_insert.each do |line|
file.puts line
end
# EOF here
file.truncate(file.pos)
end
Making use of File#pos to specify where to truncate.

How about using a temp file?
File.open("file.tmp", "w") do |tmp_file|
File.open("file.txt", "r+") do |file|
file.readlines.each do |line|
# add each line of the original file up to and including marker line
tmp_file.puts line
if line.include? "marker" #or however you're indicating marker
break
end
end
# add new lines
lines_to_insert.each do |line|
tmp_file.puts line
end
end
end
FileUtils.mv 'file.tmp', 'file.txt'
This will guarantee a file with a proper EOF line and not a hacky set of lines at the end that are nothing but newline characters or spaces.

Why not fill an array with each line, by using something like this:
array = file.split("\\\n")
Then you can just find the index of the array that contains the word marker
marker_index = array.index{|line|line.include('marker')}
Then just add random values to any index > marker_index
Finally concatenate all the strings in your array (don't forget to add your \n back in) and write back to your file.

Related

Ruby filtering specific lines from a text file

I'm a newbie! I have a text file that contains lines and lines of text. I want to try to create a code that only allows the lines that have the phrase "larry.bird" show while the others are deleted. This is my current code...
File.open("HM.txt").each do |line|
   puts line
   if line.include? "larry.bird"
      puts "larye.bird " + line
   end
end
File.readlines('HM.txt') do |li|
  puts li if (li['larry.bird'])
end
If you can help me out, that would be awesome!
You're pretty close. You're opening and reading the file correctly; you're just accidentally printing every line before performing the check. The puts line on the second line of your code is ensuring that this occurs.
File.open("HM.txt") do |file|
file.each_line do |line|
if line.include? "larry.bird"
puts "larry.bird " + line
end
end
end
We can also shorten one-line if statements in Ruby, using suffix notation that often makes code more concise.
File.open("HM.txt") do |file|
file.each_line do |line|
puts "larry.bird " + line if line.include? "larry.bird"
end
end
This is equivalent to the first example.

Ruby read file line issue

I'm trying to read a file into a string. For instance, I tried reading this file:
123456
23456
3456
456
56
6
I tried:
contents = File.open("test.txt", "rb").read
print contents
IO.foreach('test.txt') do |line|
print line
end
File.open('test.txt', 'r').each_line do |line|
print line
end
but I seem to get a single line that will overwrite it's contents with each new line. I get 666666.
The issue has to be the fact that the file is using the CR line terminator (or your terminal is messed up and not responding to LF). print does not go into the new line by default (you should use puts if that's what you want), and each_line does not strip the line terminator. So what happens is, print "123456\r" prints out 123456 and then returns the cursor to the start of the line, without moving to the next line (so the cursor is on 1. Then when you print "23456\r", it will overwrite the first five characters and again come back to the start, the current state being 234566... In the end, 566666 will get overwritten by "6\r" for the final 666666.
Why not try the simple solution
# ruby sample code.
# process every line in a text file with ruby (version 1).
file='test.txt'
File.readlines(file).each do |line|
puts line
end
Second approach
# ruby sample code.
# process every line in a text file with ruby (version 2).
file='test.txt'
f = File.open(file, "r")
f.each_line { |line|
puts line
}
f.close
Answer Source

reading text file lines in ruby

I would like to scan each line in a text file, EXCEPT the first line.
I would usually do:
while line = file.gets do
...
...etc
end
but line = file.gets reads EVERY single line starting from the first.
How do I read from the second line onwards?
Why not simply call file.gets once and discard the result:
file.gets
while line = file.gets
# code here
end
I would do it in a simple fashion:
IO.readlines('filename').drop(1).each do |line| # drop the first array element
# do any proc here
end
Do you actually want to avoid reading the first line or avoid doing something with it. If you are OK reading the line but you want to avoid processing it then you can use lineno to ignore the line during processing as follows
f = File.new "/tmp/xx"
while line = f.gets do
puts line unless f.lineno == 1
end

Deleting a specific line in a text file?

How can I delete a single, specific line from a text file? For example the third line, or any other line. I tried this:
line = 2
file = File.open(filename, 'r+')
file.each { last_line = file.pos unless file.eof? }
file.seek(last_line, IO::SEEK_SET)
file.close
Unfortunately, it does nothing. I tried a lot of other solutions, but nothing works.
I think you can't do that safely because of file system limitations.
If you really wanna do a inplace editing, you could try to write it to memory, edit it, and then replace the old file. But beware that there's at least two problems with this approach. First, if your program stops in the middle of rewriting, you will get an incomplete file. Second, if your file is too big, it will eat your memory.
file_lines = ''
IO.readlines(your_file).each do |line|
file_lines += line unless <put here your condition for removing the line>
end
<extra string manipulation to file_lines if you wanted>
File.open(your_file, 'w') do |file|
file.puts file_lines
end
Something along those lines should work, but using a temporary file is a much safer and the standard approach
require 'fileutils'
File.open(output_file, "w") do |out_file|
File.foreach(input_file) do |line|
out_file.puts line unless <put here your condition for removing the line>
end
end
FileUtils.mv(output_file, input_file)
Your condition could be anything that showed it was the unwanted line, like, file_lines += line unless line.chomp == "aaab" for example, would remove the line "aaab".

Ruby console overwrites line when printing out lines in a file

I have started learning Ruby and I have come across an annoying problem. I have imported a text file into my program and I want to iterate over the lines in it and print them out to the screen.
When I do this, the console overwrites the last printed out line and writes the new one on top. Why is this happening and how can I solve it?
Here is my code:
passwords = File.open('C:\Users\Ryan\Desktop\pw.txt', 'r')
lines = passwords.gets
for line in lines
puts line
end
Update:
The loop is acting very strange. I put a sleep statement into it and all it did was sleep once then continue to output the lines. I would have expected it to sleep before outputting each line. Example below:
passwords.each do |line|
sleep 1
puts line.chomp
end
Update 2:
I just created a new text file and typed some random stuff into it for testing and it works fine. Looks like the original file had some bad characters/encoding which messed up the printing to the console.
Do you have an EOL (AKA end-of-line) problem? Try this:
passwords = File.open('C:\Users\Ryan\Desktop\pw.txt', 'r')
lines = passwords.gets
lines.each { |line| puts line.chomp }
passwords.close
The chomp call will strip off any \n, \r, or \r\n line endings, then puts will append the native EOL.
File.open('C:\Users\Ryan\Desktop\pw.txt') do |line|
while not line.eof?
puts line.readline.chomp
end
end
or
File.read("file").each { |line| puts line.chomp }
In the end I found out that the text file was the cause of my problem. I created a new one with the same content and it started working how I intended.

Resources