I have a large file with alot of lines.
But now I want to read the file from the endline towards the beginning line, this line by line.
How do I do this ?
This is very difficult, and unfortunately seems like nobody has implemented a library.
But there’s this tac
command that’s typically on Linux, which I think reverse streams a file, so it could be used.
Process.run("tac", ["foo.txt"]) do |tac|
tac.output.each_line do |line|
...
end
end
The following worked :
Blockquote
Process.run(“rev”, [“/var/log/messages”]) do |r|
r.output.each_line do |line|
puts line.reverse
end
end
Then you can use directly String#reverse
.
A not the most efficient, simple Crystal native implementation:
str = File.read "./README.md"
while true
str, _, last_line = str.rpartition '\n'
break if str.empty? && last_line.empty?
puts last_line
end
@j8r OP wants to avoid reading the file into memory because it’s huge
Ok, sure, can be read by chunks, something like this?:
bytesize = 32
last_string = ""
break_next = false
File.open "./README.md" do |file|
offset = file.size.to_i - bytesize
while true
file.read_at offset, bytesize do |io|
string = io.gets_to_end + last_string
while true
string, _, last_line = string.rpartition '\n'
if string.empty?
last_string = last_line
break
end
puts last_line
end
end
offset -= bytesize
if break_next
break
elsif offset <= 0
bytesize += offset
offset = 0
break_next = true
end
end
puts last_string
end
You can skip to EOF and read lines backwards, essentially IO#gets
with inverse direction.
This is a old library from the Ruby world for doing operations to do just that, so it might be of some use to you:
Not sure if it would translate to Crystal properly, but something to consider.