1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package mk.fsgrep.util;
26
27 import java.io.*;
28 import java.util.*;
29
30 /***
31 * A utility that fully reads a file and provides access to the contents
32 * as a List of lines.
33 * It is meant to replace LineNumberReader and (its parent) BufferedReader
34 * because those consume the EOL characters when returning lines.
35 *
36 * @author Murali Krishnan
37 *
38 */
39 public class RawLineReader {
40
41
42
43
44 private static final int BUFFER_SIZE = 36;
45 private static final char CR = '\r';
46 private static final char LF = '\n';
47
48
49
50
51
52
53
54
55
56
57 private File vFile = null;
58 private LinkedList<FileLine> vLines = new LinkedList<FileLine>();
59 private int vSize = 0;
60
61
62
63
64
65 public RawLineReader(String pFileName) {
66 this(new File(pFileName));
67 }
68
69
70 public RawLineReader(File pFile) {
71 vFile = pFile;
72
73 initialize();
74 }
75
76
77 /***
78 * For testing only.
79 *
80 */
81 protected RawLineReader() {
82 }
83
84
85
86
87
88 protected File getFile() {
89 return vFile;
90 }
91
92 public int getSize() {
93 return vSize;
94 }
95
96 protected LinkedList<FileLine> getLines() {
97 return vLines;
98 }
99
100
101
102
103
104
105 public void setSize(int val) {
106 vSize = val;
107 }
108
109
110
111
112
113
114 protected void initialize() {
115 try {
116 FileReader fr = new FileReader(getFile());
117 initialize(fr);
118 fr.close();
119 } catch (IOException ioe) {
120 System.err.println("Problem reading [" + getFileName() + "].");
121 ioe.printStackTrace();
122 }
123 }
124
125
126 protected void initialize(Reader reader) throws IOException {
127 int size = 0;
128 char[] buffer = new char[BUFFER_SIZE];
129 Splitter splitter = new Splitter(getLines());
130
131 boolean done;
132 do {
133 int charsRead = reader.read(buffer);
134 done = (charsRead == -1);
135 if (done) {
136 if (splitter.hasRemainder()) {
137 getLines().add(splitter.giveRemainder());
138 }
139 } else {
140 size += charsRead;
141 splitter.add(buffer, charsRead);
142 }
143 } while(!done);
144
145 setSize(size);
146 }
147
148
149 protected void initialize(String content) {
150 try {
151 StringReader reader = new StringReader(content);
152 initialize(reader);
153 reader.close();
154 } catch (IOException ioe) {
155 System.err.println("Problem reading content.");
156 ioe.printStackTrace();
157 }
158 }
159
160
161 protected String getFileName() {
162 String result = getFile().getAbsolutePath();
163 return result;
164 }
165
166
167 protected void saveTo(String pString) {
168 try {
169 FileWriter fw = new FileWriter(pString);
170 for (FileLine line : getLines()) {
171 fw.write(line.getText());
172 }
173 fw.close();
174 } catch (Exception ex) {
175 ex.printStackTrace();
176 }
177 }
178
179
180
181
182
183 public String toString() {
184 String result = "RawLineReader[name=" + getFileName() + ",lines=" + getLines().size() + ",characters=" + getSize() + "]";
185 return result;
186 }
187
188
189 public boolean hasMore() {
190 boolean result = !getLines().isEmpty();
191 return result;
192 }
193
194
195 public FileLine nextLine() {
196 return getLines().removeFirst();
197 }
198
199
200
201
202
203
204
205
206
207
208 private class Splitter {
209 private StringBuffer vRemainder = new StringBuffer();
210 private char vLastRemainderChar = Character.MIN_VALUE;
211 private char[] vBuffer = null;
212 private int vStart = 0;
213 private int vCurrent = 0;
214 private int vEnd = 0;
215 private int vLineNumber = 0;
216 private LinkedList<FileLine> vBufferLines = null;
217
218 public Splitter(LinkedList<FileLine> pBufferLines) {
219 vBufferLines = pBufferLines;
220 }
221
222
223 private boolean currentIs(char ch) {
224 boolean result = vBuffer[vCurrent] == ch;
225 return result;
226 }
227
228 private boolean nextIs(char ch) {
229 int next = vCurrent + 1;
230 boolean result = (next < vEnd) && (vBuffer[next] == ch);
231 return result;
232 }
233
234 private boolean atEol() {
235 boolean result = currentIs(LF) ||
236 (currentIs(CR) && !nextIs(LF));
237 return result;
238 }
239
240 private boolean atEob() {
241 boolean result = (vCurrent >= vEnd);
242 return result;
243 }
244
245 public boolean hasRemainder() {
246 boolean result = (vRemainder.length() > 0);
247 return result;
248 }
249
250
251 public FileLine giveRemainder() {
252 FileLine result = new FileLine(++vLineNumber, vRemainder.toString());
253 vRemainder = new StringBuffer();
254 return result;
255 }
256
257 public boolean needToProcess() {
258 boolean result = true;
259
260 while (!(atEob() || atEol())) {
261 vCurrent++;
262 }
263
264 if (atEob()) {
265 result = false;
266 --vCurrent;
267
268 int length = (vCurrent-vStart+1);
269 if (length > 0) {
270 vRemainder.append(new String(vBuffer, vStart, length));
271 } else {
272
273 vLastRemainderChar = vBuffer[vCurrent];
274 }
275 } else {
276 int length = (vCurrent-vStart+1);
277 String text = new String(vBuffer, vStart, length);
278 if (vRemainder.length() > 0) {
279 text = vRemainder + text;
280 vRemainder = new StringBuffer();
281 }
282
283 vStart = ++vCurrent;
284
285 FileLine newLine = new FileLine(++vLineNumber, text);
286 vBufferLines.add(newLine);
287 }
288
289 return result;
290 }
291
292
293 public boolean hasMore() {
294 boolean result = !vBufferLines.isEmpty();
295 return result;
296 }
297
298
299 public FileLine nextLine() {
300 return vBufferLines.removeFirst();
301 }
302
303
304 public void add(char[] buffer, int len) {
305 vBuffer = buffer;
306 vStart = 0;
307 vCurrent = 0;
308 vEnd = len;
309
310
311 if ((vLastRemainderChar == CR) && (buffer[0] == LF)) {
312
313
314 FileLine last = vBufferLines.getLast();
315 last.setText(last.getText() + LF);
316
317
318 vStart = 1;
319 vCurrent = 1;
320 }
321
322
323 while (needToProcess());
324 }
325 }
326
327
328
329
330
331 public static void main(String[] args) {
332 try {
333 for (String arg : args) {
334 RawLineReader rlr = new RawLineReader(arg);
335 System.out.println(rlr);
336 rlr.saveTo("testout.txt");
337 }
338
339 } catch (Throwable thr) {
340 System.err.println("Fatal error.");
341 thr.printStackTrace();
342 }
343 }
344
345
346
347 }