View Javadoc
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 }