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
Related
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.
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
I want to grab only the first line of columns 46 to 245 of source.txt and write it to output.txt
source_file.each { |line|
File.open(output_file,"a+") { |f|
f.print ???
}
Bonus: I also need to keep a count of the number of characters in this range, as some may be whitespace. i.e. 38 characters and the rest whitespace.
Example:
source_file: (first line only, columns 45 to 245): 13287912721981239854 + 180 blank columns
output_file: 13287912721981239854
count = 20 characters
Update: appending [46..245].delete(' ').size gives me the desired count.
If I am understanding what you are asking correctly, there's no reason to grab the whole file when you only want the first line. If this isn't what you're asking for, then you need to specify what you're trying to pull out of the source file more clearly.
This should grab the data you need:
output_line = source_file.gets [45..244]
If you write:
source_file.each { |line|
File.open(output_file,"a+") { |f|
f.print ???
}
}
You will open, then close, your output file for each line read from the output file. That is the wrong way to do it, even if you only want to read one line of input.
Instead try something like one of these:
File.open(output_file, 'a') do |fo|
File.open('path/to/input_file') do |fi|
fo.puts fi.readline[46..245]
end
end
This uses IO.readline, which reads a single line from the file. The block falls through afterwards, causing both the input and output files to be closed automatically. Also, it opens the output file as 'a' which is append-mode only. 'a+' is wrong unless you intend to append and read, which is rarely done. From the documentation:
"a+" Read-write, starts at end of file if file exists,
otherwise creates a new file for reading and
writing
Or:
File.open(output_file, 'a') do |fo|
File.foreach('path/to/input_file') do |li|
fo.puts li[46..245]
break
end
end
foreach is used most often when we're reading a file line-by-line. It's the mainstay for reading files in a scalable manner. It wants to loop over the file inside the block, which is why break is there, to break out of that loop.
Or:
File.foreach('path/to/input_file') do |li|
File.write(output_file, li[46..245], -1, :mode => 'a')
break
end
File.write is useful when you have a blob of text or binary, and want to write it in one chunk, then move on. The -1 tells Ruby to move to the end of the file. :mode => 'a' overrides the default mode which would normally truncate an existing file.
Maybe this will do the job:
line = f.readline
columns = line.split
File.open("output.txt", "w") do |out|
columns[46, (245 - 46 + 1)].each do |column|
out.puts column
end
end
break # only process first line
I have used 245 - 46 + 1 to indicate this is the number of columns we are interested in. I have also assumed that columns are separate by whitespaces. If that is not the case you will need to change the delimiter of split.
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.
I was trying to use the following code to read lines from a file. But when reading a file, the contents are all in one line:
line_num=0
File.open('xxx.txt').each do |line|
print "#{line_num += 1} #{line}"
end
But this file prints each line separately.
I have to use stdin, like ruby my_prog.rb < file.txt, where I can't assume what the line-ending character is that the file uses. How can I handle it?
Ruby does have a method for this:
File.readlines('foo').each do |line|
puts(line)
end
http://ruby-doc.org/core-1.9.3/IO.html#method-c-readlines
File.foreach(filename).with_index do |line, line_num|
puts "#{line_num}: #{line}"
end
This will execute the given block for each line in the file without slurping the entire file into memory. See: IO::foreach.
I believe my answer covers your new concerns about handling any type of line endings since both "\r\n" and "\r" are converted to Linux standard "\n" before parsing the lines.
To support the "\r" EOL character along with the regular "\n", and "\r\n" from Windows, here's what I would do:
line_num=0
text=File.open('xxx.txt').read
text.gsub!(/\r\n?/, "\n")
text.each_line do |line|
print "#{line_num += 1} #{line}"
end
Of course this could be a bad idea on very large files since it means loading the whole file into memory.
Your first file has Mac Classic line endings (that’s "\r" instead of the usual "\n"). Open it with
File.open('foo').each(sep="\r") do |line|
to specify the line endings.
I'm partial to the following approach for files that have headers:
File.open(file, "r") do |fh|
header = fh.readline
# Process the header
while(line = fh.gets) != nil
#do stuff
end
end
This allows you to process a header line (or lines) differently than the content lines.
It is because of the endlines in each lines.
Use the chomp method in ruby to delete the endline '\n' or 'r' at the end.
line_num=0
File.open('xxx.txt').each do |line|
print "#{line_num += 1} #{line.chomp}"
end
how about gets ?
myFile=File.open("paths_to_file","r")
while(line=myFile.gets)
//do stuff with line
end
Don't forget that if you are concerned about reading in a file that might have huge lines that could swamp your RAM during runtime, you can always read the file piece-meal. See "Why slurping a file is bad".
File.open('file_path', 'rb') do |io|
while chunk = io.read(16 * 1024) do
something_with_the chunk
# like stream it across a network
# or write it to another file:
# other_io.write chunk
end
end