Class: File
Instance Method Summary collapse
-
#reverse_each(&block) ⇒ Object
A streaming
reverse_eachimplementation. -
#reverse_each_from_current_pos {|fragment| ... } ⇒ Object
Read each line of file backwards (from the current position.).
-
#reverse_read(length, block_aligned = false) ⇒ Object
Read the previous
lengthbytes. -
#reverse_readline ⇒ Object
Read the previous line (leaving
posat the beginning of the string that was read.). -
#seek_backwards_to(string, blocksize = 512, rindex_end = -1)) ⇒ Object
Scan backwards in the file until
stringis found, and set the IO’sposto the first character after the matched string. -
#seek_end ⇒ Object
Seek to
EOF. -
#seek_start ⇒ Object
Seek to
BOF.
Instance Method Details
#reverse_each(&block) ⇒ Object
A streaming reverse_each implementation. (For large files, it’s faster and uses less memory.)
13 14 15 16 17 18 |
# File 'lib/epitools/core_ext/file.rb', line 13 def reverse_each(&block) return to_enum(:reverse_each) unless block_given? seek_end reverse_each_from_current_pos(&block) end |
#reverse_each_from_current_pos {|fragment| ... } ⇒ Object
Read each line of file backwards (from the current position.)
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/epitools/core_ext/file.rb', line 54 def reverse_each_from_current_pos return to_enum(:reverse_each_from_current_pos) unless block_given? # read the rest of the current line, in case we started in the middle of a line start_pos = pos fragment = readline rescue "" seek(start_pos) while data = reverse_read(4096) lines = data.each_line.to_a lines.last << fragment unless lines.last[-1] == "\n" fragment = lines.first lines[1..-1].reverse_each { |line| yield line } end yield fragment end |
#reverse_read(length, block_aligned = false) ⇒ Object
Read the previous length bytes. After the read, pos will be at the beginning of the region that you just read. Returns nil when the beginning of the file is reached.
If the block_aligned argument is true, reads will always be aligned to file positions which are multiples of 512 bytes. (This should increase performance slightly.)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/epitools/core_ext/file.rb', line 27 def reverse_read(length, block_aligned=false) raise "length must be a multiple of 512" if block_aligned and length % 512 != 0 end_pos = pos return nil if end_pos == 0 if block_aligned misalignment = end_pos % length length += misalignment end if length >= end_pos # this read will take us to the beginning of the file seek(0) else seek(-length, IO::SEEK_CUR) end start_pos = pos data = read(end_pos - start_pos) seek(start_pos) data end |
#reverse_readline ⇒ Object
Read the previous line (leaving pos at the beginning of the string that was read.)
91 92 93 94 95 96 97 98 99 |
# File 'lib/epitools/core_ext/file.rb', line 91 def reverse_readline raise BOFError.new("beginning of file reached") if pos == 0 seek_backwards_to("\n", 512, -2) new_pos = pos data = readline seek(new_pos) data end |
#seek_backwards_to(string, blocksize = 512, rindex_end = -1)) ⇒ Object
Scan backwards in the file until string is found, and set the IO’s pos to the first character after the matched string.
104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/epitools/core_ext/file.rb', line 104 def seek_backwards_to(string, blocksize=512, rindex_end=-1) loop do data = reverse_read(blocksize) if index = data.rindex(string, rindex_end) seek(index+string.size, IO::SEEK_CUR) break elsif pos == 0 break end end end |
#seek_end ⇒ Object
Seek to EOF
77 78 79 |
# File 'lib/epitools/core_ext/file.rb', line 77 def seek_end seek(0, IO::SEEK_END) end |
#seek_start ⇒ Object
Seek to BOF
84 85 86 |
# File 'lib/epitools/core_ext/file.rb', line 84 def seek_start seek(0) end |