1 /*
2 * #%L
3 * Nuiton Utils
4 * %%
5 * Copyright (C) 2004 - 2011 CodeLutin, Chatellier Eric
6 * %%
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Lesser Public License for more details.
16 *
17 * You should have received a copy of the GNU General Lesser Public
18 * License along with this program. If not, see
19 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20 * #L%
21 */
22
23 package org.nuiton.util;
24
25 import java.io.Closeable;
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.RandomAccessFile;
29
30 /**
31 * Reverse file reader.
32 *
33 * Read file line by line for end of file to begin of file.
34 *
35 * @author chatellier
36 */
37 public class ReverseFileReader implements Closeable {
38 protected String filename;
39
40 protected RandomAccessFile randomfile;
41
42 protected long position;
43
44 public ReverseFileReader(File file) throws IOException {
45 // Open up a random access file
46 randomfile = new RandomAccessFile(file, "r");
47 // Set our seek position to the end of the file
48 position = randomfile.length();
49
50 // Seek to the end of the file
51 randomfile.seek(position);
52 //Move our pointer to the first valid position at the end of the file.
53 String thisLine = randomfile.readLine();
54 while (thisLine == null) {
55 position--;
56 randomfile.seek(position);
57 thisLine = randomfile.readLine();
58 randomfile.seek(position);
59 }
60 }
61
62 public ReverseFileReader(String filename) throws IOException {
63 this(filename != null ? new File(filename) : null);
64 }
65
66 /**
67 * Read one line from the current position towards the beginning.
68 *
69 * @return the next line of text from this file, or null if end of file is
70 * encountered before even one byte is read.
71 * @throws IOException if any pb while reading line
72 */
73 public String readLine() throws IOException {
74 int thisCode;
75 char thisChar;
76 String finalLine = "";
77
78 // If our position is less than zero already, we are at the beginning
79 // with nothing to return.
80 if (position < 0) {
81 return null;
82 }
83
84 for (; ; ) {
85 // we've reached the beginning of the file
86 if (position < 0) {
87 break;
88 }
89 // Seek to the current position
90 randomfile.seek(position);
91
92 // Read the data at this position
93 thisCode = randomfile.readByte();
94 thisChar = (char) thisCode;
95
96 // If this is a line break or carrige return, stop looking
97 if (thisCode == 13 || thisCode == 10) {
98 // See if the previous character is also a line break character.
99 // this accounts for crlf combinations
100 randomfile.seek(position - 1);
101 int nextCode = randomfile.readByte();
102 if (thisCode == 10 && nextCode == 13
103 || thisCode == 13 && nextCode == 10) {
104 // If we found another linebreak character, ignore it
105 position = position - 1;
106 }
107 // Move the pointer for the next readline
108 position--;
109 break;
110 } else {
111 // This is a valid character append to the string
112 finalLine = thisChar + finalLine;
113 }
114 // Move to the next char
115 position--;
116 }
117 // return the line
118 return finalLine;
119 }
120
121 @Override
122 public void close() throws IOException {
123 if (randomfile != null) {
124 randomfile.close();
125 }
126 }
127
128 @Override
129 protected void finalize() throws Throwable {
130 close();
131 super.finalize();
132 }
133 }