1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.archive.crawler.util;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.FileReader;
25 import java.io.IOException;
26 import java.io.InputStreamReader;
27 import java.io.RandomAccessFile;
28 import java.text.DecimalFormat;
29 import java.text.NumberFormat;
30 import java.util.LinkedList;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33 import java.util.regex.PatternSyntaxException;
34
35 import org.archive.crawler.framework.CrawlController;
36 import org.archive.io.CompositeFileReader;
37 import org.archive.util.ArchiveUtils;
38
39 /***
40 * This class contains a variety of methods for reading log files (or other text
41 * files containing repeated lines with similar information).
42 * <p>
43 * All methods are static.
44 *
45 * @author Kristinn Sigurdsson
46 */
47
48 public class LogReader
49 {
50 /***
51 * Returns the entire file. Useful for smaller files.
52 *
53 * @param aFileName a file name
54 * @return The String representation of the entire file.
55 * Null is returned if errors occur (file not found or io exception)
56 */
57 public static String get(String aFileName){
58 try {
59 return get(new FileReader(aFileName));
60 } catch (FileNotFoundException e) {
61 e.printStackTrace();
62 return null;
63 }
64 }
65
66 /***
67 * Reads entire contents of reader, returns as string.
68 *
69 * @param reader
70 * @return String of entire contents; null for any error.
71 */
72 public static String get(InputStreamReader reader){
73 StringBuffer ret = new StringBuffer();
74 try{
75 BufferedReader bf = new BufferedReader(reader, 8192);
76
77 String line = null;
78 while ((line = bf.readLine()) != null) {
79 ret.append(line);
80 ret.append("\n");
81 }
82 } catch(IOException e){
83 e.printStackTrace();
84 return null;
85 }
86 return ret.toString();
87 }
88
89 /***
90 * Gets a portion of a log file. Starting at a given line number and the n-1
91 * lines following that one or until the end of the log if that is reached
92 * first.
93 *
94 * @param aFileName The filename of the log/file
95 * @param lineNumber The number of the first line to get (if larger then the
96 * file an empty string will be returned)
97 * @param n How many lines to return (total, including the one indicated by
98 * lineNumber). If smaller then 1 then an empty string
99 * will be returned.
100 *
101 * @return An array of two strings is returned. At index 0 a portion of the
102 * file starting at lineNumber and reaching lineNumber+n is located.
103 * At index 1 there is an informational string about how large a
104 * segment of the file is being returned.
105 * Null is returned if errors occur (file not found or io exception)
106 */
107 public static String[] get(String aFileName, int lineNumber, int n)
108 {
109 File f = new File(aFileName);
110 long logsize = f.length();
111 try {
112 return get(new FileReader(aFileName),lineNumber,n,logsize);
113 } catch (FileNotFoundException e) {
114 e.printStackTrace();
115 return null;
116 }
117 }
118
119 /***
120 * Gets a portion of a log spread across a numbered series of files.
121 *
122 * Starting at a given line number and the n-1 lines following that
123 * one or until the end of the log if that is reached
124 * first.
125 *
126 * @param aFileName The filename of the log/file
127 * @param lineNumber The number of the first line to get (if larger then the
128 * file an empty string will be returned)
129 * @param n How many lines to return (total, including the one indicated by
130 * lineNumber). If smaller then 1 then an empty string
131 * will be returned.
132 *
133 * @return An array of two strings is returned. At index 0 a portion of the
134 * file starting at lineNumber and reaching lineNumber+n is located.
135 * At index 1 there is an informational string about how large a
136 * segment of the file is being returned.
137 * Null is returned if errors occur (file not found or io exception)
138 */
139 public static String[] getFromSeries(String aFileName, int lineNumber, int n)
140 {
141 File f = new File(aFileName);
142 long logsize = f.length();
143 try {
144 return get(seriesReader(aFileName),lineNumber,n,logsize);
145 } catch (IOException e) {
146 e.printStackTrace();
147 return null;
148 }
149 }
150
151 public static String buildDisplayingHeader(int len, long logsize)
152 {
153 double percent = 0.0;
154 if (logsize != 0) {
155 percent = ((double) len/logsize) * 100;
156 }
157 return "Displaying: " + ArchiveUtils.doubleToString(percent,1) +
158 "% of " + ArchiveUtils.formatBytesForDisplay(logsize);
159 }
160
161 /***
162 * Gets a portion of a log file. Starting at a given line number and the n-1
163 * lines following that one or until the end of the log if that is reached
164 * first.
165 *
166 * @param reader source to scan for lines
167 * @param lineNumber The number of the first line to get (if larger then the
168 * file an empty string will be returned)
169 * @param n How many lines to return (total, including the one indicated by
170 * lineNumber). If smaller then 1 then an empty string
171 * will be returned.
172 *
173 * @param logsize total size of source
174 * @return An array of two strings is returned. At index 0 a portion of the
175 * file starting at lineNumber and reaching lineNumber+n is located.
176 * At index 1 there is an informational string about how large a
177 * segment of the file is being returned.
178 * Null is returned if errors occur (file not found or io exception)
179 */
180 public static String[] get(InputStreamReader reader,
181 int lineNumber,
182 int n,
183 long logsize)
184 {
185 StringBuffer ret = new StringBuffer();
186 String info = null;
187 try{
188 BufferedReader bf = new BufferedReader(reader, 8192);
189
190 String line = null;
191 int i=1;
192 while ((line = bf.readLine()) != null) {
193 if(i >= lineNumber && i < (lineNumber+n))
194 {
195 ret.append(line);
196 ret.append('\n');
197 } else if( i >= (lineNumber+n)){
198 break;
199 }
200 i++;
201 }
202 info = buildDisplayingHeader(ret.length(), logsize);
203 }catch(IOException e){
204 e.printStackTrace();
205 return null;
206 }
207 String[] tmp = {ret.toString(),info};
208 return tmp;
209 }
210
211 /***
212 * Return the line number of the first line in the
213 * log/file that matches a given regular expression.
214 *
215 * @param aFileName The filename of the log/file
216 * @param regExpr The regular expression that is to be used
217 * @return The line number (counting from 1, not zero) of the first line
218 * that matches the given regular expression. -1 is returned if no
219 * line matches the regular expression. -1 also is returned if
220 * errors occur (file not found, io exception etc.)
221 */
222 public static int findFirstLineContaining(String aFileName, String regExpr)
223 {
224 try {
225 return findFirstLineContaining(new FileReader(aFileName), regExpr);
226 } catch (FileNotFoundException e) {
227 e.printStackTrace();
228 return -1;
229 }
230 }
231
232 /***
233 * Return the line number of the first line in the
234 * log/file that begins with the given string.
235 *
236 * @param aFileName The filename of the log/file
237 * @param prefix The prefix string to match
238 * @return The line number (counting from 1, not zero) of the first line
239 * that matches the given regular expression. -1 is returned if no
240 * line matches the regular expression. -1 also is returned if
241 * errors occur (file not found, io exception etc.)
242 */
243 public static int findFirstLineBeginningFromSeries(String aFileName,
244 String prefix)
245 {
246 try {
247 return findFirstLineBeginning(seriesReader(aFileName), prefix);
248 } catch (IOException e) {
249 e.printStackTrace();
250 return -1;
251 }
252 }
253
254 /***
255 * Return the line number of the first line in the
256 * log/file that that begins with the given string.
257 *
258 * @param reader The reader of the log/file
259 * @param prefix The prefix string to match
260 * @return The line number (counting from 1, not zero) of the first line
261 * that matches the given regular expression. -1 is returned if no
262 * line matches the regular expression. -1 also is returned if
263 * errors occur (file not found, io exception etc.)
264 */
265 public static int findFirstLineBeginning(InputStreamReader reader,
266 String prefix)
267 {
268
269 try{
270 BufferedReader bf = new BufferedReader(reader, 8192);
271
272 String line = null;
273 int i = 1;
274 while ((line = bf.readLine()) != null) {
275 if(line.startsWith(prefix)){
276
277 return i;
278 }
279 i++;
280 }
281 } catch(IOException e){
282 e.printStackTrace();
283 }
284 return -1;
285 }
286
287 /***
288 * Return the line number of the first line in the
289 * log/file that matches a given regular expression.
290 *
291 * @param aFileName The filename of the log/file
292 * @param regExpr The regular expression that is to be used
293 * @return The line number (counting from 1, not zero) of the first line
294 * that matches the given regular expression. -1 is returned if no
295 * line matches the regular expression. -1 also is returned if
296 * errors occur (file not found, io exception etc.)
297 */
298 public static int findFirstLineContainingFromSeries(String aFileName,
299 String regExpr)
300 {
301 try {
302 return findFirstLineContaining(seriesReader(aFileName), regExpr);
303 } catch (IOException e) {
304 e.printStackTrace();
305 return -1;
306 }
307 }
308
309 /***
310 * Return the line number of the first line in the
311 * log/file that matches a given regular expression.
312 *
313 * @param reader The reader of the log/file
314 * @param regExpr The regular expression that is to be used
315 * @return The line number (counting from 1, not zero) of the first line
316 * that matches the given regular expression. -1 is returned if no
317 * line matches the regular expression. -1 also is returned if
318 * errors occur (file not found, io exception etc.)
319 */
320 public static int findFirstLineContaining(InputStreamReader reader,
321 String regExpr)
322 {
323 Pattern p = Pattern.compile(regExpr);
324
325 try{
326 BufferedReader bf = new BufferedReader(reader, 8192);
327
328 String line = null;
329 int i = 1;
330 while ((line = bf.readLine()) != null) {
331 if(p.matcher(line).matches()){
332
333 return i;
334 }
335 i++;
336 }
337 } catch(IOException e){
338 e.printStackTrace();
339 }
340 return -1;
341 }
342
343 /***
344 * Returns all lines in a log/file matching a given regular expression.
345 * Possible to get lines immediately following the matched line. Also
346 * possible to have each line prepended by it's line number.
347 *
348 * @param aFileName The filename of the log/file
349 * @param regExpr The regular expression that is to be used
350 * @param addLines How many lines (in addition to the matched line) to add.
351 * A value less then 1 will mean that only the matched line
352 * will be included. If another matched line is hit before
353 * we reach this limit it will be included and this counter
354 * effectively reset for it.
355 * @param prependLineNumbers If true, then each line will be prepended by
356 * it's line number in the file.
357 * @param skipFirstMatches The first number of matches up to this value will
358 * be skipped over.
359 * @param numberOfMatches Once past matches that are to be skipped this many
360 * matches will be added to the return value. A
361 * value of 0 will cause all matching lines to be
362 * included.
363 * @return An array of two strings is returned. At index 0 tall lines in a
364 * log/file matching a given regular expression is located.
365 * At index 1 there is an informational string about how large a
366 * segment of the file is being returned.
367 * Null is returned if errors occur (file not found or io exception)
368 * If a PatternSyntaxException occurs, it's error message will be
369 * returned and the informational string will be empty (not null).
370 */
371 public static String[] getByRegExpr(String aFileName,
372 String regExpr,
373 int addLines,
374 boolean prependLineNumbers,
375 int skipFirstMatches,
376 int numberOfMatches) {
377 try {
378 File f = new File(aFileName);
379 return getByRegExpr(
380 new FileReader(f),
381 regExpr,
382 addLines,
383 prependLineNumbers,
384 skipFirstMatches,
385 numberOfMatches,
386 f.length());
387 } catch (FileNotFoundException e) {
388 e.printStackTrace();
389 return null;
390 }
391 }
392
393 /***
394 * Returns all lines in a log/file matching a given regular expression.
395 * Possible to get lines immediately following the matched line. Also
396 * possible to have each line prepended by it's line number.
397 *
398 * @param aFileName The filename of the log/file
399 * @param regExpr The regular expression that is to be used
400 * @param addLines How many lines (in addition to the matched line) to add.
401 * A value less then 1 will mean that only the matched line
402 * will be included. If another matched line is hit before
403 * we reach this limit it will be included and this counter
404 * effectively reset for it.
405 * @param prependLineNumbers If true, then each line will be prepended by
406 * it's line number in the file.
407 * @param skipFirstMatches The first number of matches up to this value will
408 * be skipped over.
409 * @param numberOfMatches Once past matches that are to be skipped this many
410 * matches will be added to the return value. A
411 * value of 0 will cause all matching lines to be
412 * included.
413 * @return An array of two strings is returned. At index 0 tall lines in a
414 * log/file matching a given regular expression is located.
415 * At index 1 there is an informational string about how large a
416 * segment of the file is being returned.
417 * Null is returned if errors occur (file not found or io exception)
418 * If a PatternSyntaxException occurs, it's error message will be
419 * returned and the informational string will be empty (not null).
420 */
421 public static String[] getByRegExprFromSeries(String aFileName,
422 String regExpr,
423 int addLines,
424 boolean prependLineNumbers,
425 int skipFirstMatches,
426 int numberOfMatches) {
427 try {
428 File f = new File(aFileName);
429 return getByRegExpr(
430 seriesReader(aFileName),
431 regExpr,
432 addLines,
433 prependLineNumbers,
434 skipFirstMatches,
435 numberOfMatches,
436 f.length());
437 } catch (IOException e) {
438 e.printStackTrace();
439 return null;
440 }
441 }
442
443 /***
444 * Returns all lines in a log/file matching a given regular expression.
445 * Possible to get lines immediately following the matched line. Also
446 * possible to have each line prepended by it's line number.
447 *
448 * @param reader The reader of the log/file
449 * @param regExpr The regular expression that is to be used
450 * @param addLines How many lines (in addition to the matched line) to add.
451 * A value less then 1 will mean that only the matched line
452 * will be included. If another matched line is hit before
453 * we reach this limit it will be included and this counter
454 * effectively reset for it.
455 * @param prependLineNumbers If true, then each line will be prepended by
456 * it's line number in the file.
457 * @param skipFirstMatches The first number of matches up to this value will
458 * be skipped over.
459 * @param numberOfMatches Once past matches that are to be skipped this many
460 * matches will be added to the return value. A
461 * value of 0 will cause all matching lines to be
462 * included.
463 * @param logsize Size of the log in bytes
464 * @return An array of two strings is returned. At index 0 all lines in a
465 * log/file matching a given regular expression is located.
466 * At index 1 there is an informational string about how large a
467 * segment of the file is being returned.
468 * Null is returned if errors occur (file not found or io exception)
469 * If a PatternSyntaxException occurs, it's error message will be
470 * returned and the informational string will be empty (not null).
471 */
472 public static String[] getByRegExpr(InputStreamReader reader,
473 String regExpr,
474 int addLines,
475 boolean prependLineNumbers,
476 int skipFirstMatches,
477 int numberOfMatches,
478 long logsize) {
479 StringBuffer ret = new StringBuffer();
480 String info = "";
481
482 try{
483 Pattern p = Pattern.compile(regExpr);
484 BufferedReader bf = new BufferedReader(reader, 8192);
485
486 String line = null;
487 int i = 1;
488 boolean doAdd = false;
489 int addCount = 0;
490 long linesMatched = 0;
491 while ((line = bf.readLine()) != null) {
492 if(p.matcher(line).matches()){
493
494 if(numberOfMatches > 0 &&
495 linesMatched >= skipFirstMatches + numberOfMatches){
496
497 break;
498 }
499 linesMatched++;
500 if(linesMatched > skipFirstMatches){
501 if(prependLineNumbers){
502 ret.append(i);
503 ret.append(". ");
504 }
505 ret.append(line);
506 ret.append("\n");
507 doAdd = true;
508 addCount = 0;
509 }
510 } else if(doAdd) {
511 if(addCount < addLines){
512
513 linesMatched++;
514 if(prependLineNumbers){
515 ret.append(i);
516 ret.append(". ");
517 }
518 ret.append(line);
519 ret.append("\n");
520 }else{
521 doAdd = false;
522 addCount = 0;
523 }
524 }
525 i++;
526 }
527 info = buildDisplayingHeader(ret.length(), logsize);
528 }catch(FileNotFoundException e){
529 return null;
530 }catch(IOException e){
531 e.printStackTrace();
532 return null;
533 }catch(PatternSyntaxException e){
534 ret = new StringBuffer(e.getMessage());
535 }
536 String[] tmp = {ret.toString(),info};
537 return tmp;
538 }
539
540 /***
541 * Returns all lines in a log/file matching a given regular expression.
542 * Possible to get lines immediately following the matched line. Also
543 * possible to have each line prepended by it's line number.
544 *
545 * @param aFileName The filename of the log/file
546 * @param regExpr The regular expression that is to be used
547 * @param addLines Any lines following a match that <b>begin</b> with this
548 * string will also be included. We will stop including new
549 * lines once we hit the first that does not match.
550 * @param prependLineNumbers If true, then each line will be prepended by
551 * it's line number in the file.
552 * @param skipFirstMatches The first number of matches up to this value will
553 * be skipped over.
554 * @param numberOfMatches Once past matches that are to be skipped this many
555 * matches will be added to the return value. A
556 * value of 0 will cause all matching lines to be
557 * included.
558 * @return An array of two strings is returned. At index 0 tall lines in a
559 * log/file matching a given regular expression is located.
560 * At index 1 there is an informational string about how large a
561 * segment of the file is being returned.
562 * Null is returned if errors occur (file not found or io exception)
563 * If a PatternSyntaxException occurs, it's error message will be
564 * returned and the informational string will be empty (not null).
565 */
566 public static String[] getByRegExpr(String aFileName,
567 String regExpr,
568 String addLines,
569 boolean prependLineNumbers,
570 int skipFirstMatches,
571 int numberOfMatches){
572 try {
573 File f = new File(aFileName);
574 return getByRegExpr(
575 new FileReader(f),
576 regExpr,
577 addLines,
578 prependLineNumbers,
579 skipFirstMatches,
580 numberOfMatches,
581 f.length());
582 } catch (FileNotFoundException e) {
583 e.printStackTrace();
584 return null;
585 }
586 }
587
588 /***
589 * Returns all lines in a log/file matching a given regular expression.
590 * Possible to get lines immediately following the matched line. Also
591 * possible to have each line prepended by it's line number.
592 *
593 * @param aFileName The filename of the log/file
594 * @param regExpr The regular expression that is to be used
595 * @param addLines Any lines following a match that <b>begin</b> with this
596 * string will also be included. We will stop including new
597 * lines once we hit the first that does not match.
598 * @param prependLineNumbers If true, then each line will be prepended by
599 * it's line number in the file.
600 * @param skipFirstMatches The first number of matches up to this value will
601 * be skipped over.
602 * @param numberOfMatches Once past matches that are to be skipped this many
603 * matches will be added to the return value. A
604 * value of 0 will cause all matching lines to be
605 * included.
606 * @return An array of two strings is returned. At index 0 tall lines in a
607 * log/file matching a given regular expression is located.
608 * At index 1 there is an informational string about how large a
609 * segment of the file is being returned.
610 * Null is returned if errors occur (file not found or io exception)
611 * If a PatternSyntaxException occurs, it's error message will be
612 * returned and the informational string will be empty (not null).
613 */
614 public static String[] getByRegExprFromSeries(String aFileName,
615 String regExpr,
616 String addLines,
617 boolean prependLineNumbers,
618 int skipFirstMatches,
619 int numberOfMatches){
620 try {
621 File f = new File(aFileName);
622 return getByRegExpr(
623 seriesReader(aFileName),
624 regExpr,
625 addLines,
626 prependLineNumbers,
627 skipFirstMatches,
628 numberOfMatches,
629 f.length());
630 } catch (IOException e) {
631 e.printStackTrace();
632 return null;
633 }
634 }
635
636 /***
637 * Returns all lines in a log/file matching a given regular expression.
638 * Possible to get lines immediately following the matched line. Also
639 * possible to have each line prepended by it's line number.
640 *
641 * @param reader The reader of the log/file
642 * @param regExpr The regular expression that is to be used
643 * @param addLines Any lines following a match that <b>begin</b> with this
644 * string will also be included. We will stop including new
645 * lines once we hit the first that does not match.
646 * @param prependLineNumbers If true, then each line will be prepended by
647 * it's line number in the file.
648 * @param skipFirstMatches The first number of matches up to this value will
649 * be skipped over.
650 * @param numberOfMatches Once past matches that are to be skipped this many
651 * matches will be added to the return value. A
652 * value of 0 will cause all matching lines to be
653 * included.
654 * @param logsize Size of the log in bytes
655 * @return An array of two strings is returned. At index 0 tall lines in a
656 * log/file matching a given regular expression is located.
657 * At index 1 there is an informational string about how large a
658 * segment of the file is being returned.
659 * Null is returned if errors occur (file not found or io exception)
660 * If a PatternSyntaxException occurs, it's error message will be
661 * returned and the informational string will be empty (not null).
662 */
663 public static String[] getByRegExpr(InputStreamReader reader,
664 String regExpr,
665 String addLines,
666 boolean prependLineNumbers,
667 int skipFirstMatches,
668 int numberOfMatches,
669 long logsize) {
670 StringBuffer ret = new StringBuffer();
671 String info = "";
672 try{
673 Matcher m = Pattern.compile(regExpr).matcher("");
674 BufferedReader bf = new BufferedReader(reader, 8192);
675
676 String line = null;
677 int i = 1;
678 boolean doAdd = false;
679 long linesMatched = 0;
680 while ((line = bf.readLine()) != null) {
681 m.reset(line);
682 if(m.matches()){
683
684 if(numberOfMatches > 0 &&
685 linesMatched >= skipFirstMatches + numberOfMatches){
686
687 break;
688 }
689 linesMatched++;
690 if(linesMatched > skipFirstMatches){
691 if(prependLineNumbers){
692 ret.append(i);
693 ret.append(". ");
694 }
695 ret.append(line);
696 ret.append("\n");
697 doAdd = true;
698 }
699 } else if(doAdd) {
700 if(line.indexOf(addLines)==0){
701 linesMatched++;
702
703 if(prependLineNumbers){
704 ret.append(i);
705 ret.append(". ");
706 }
707 ret.append(line);
708 ret.append("\n");
709 }else{
710 doAdd = false;
711 }
712 }
713 i++;
714 }
715 info = buildDisplayingHeader(ret.length(), logsize);
716 }catch(FileNotFoundException e){
717 return null;
718 }catch(IOException e){
719 e.printStackTrace();
720 return null;
721 }catch(PatternSyntaxException e){
722 ret = new StringBuffer(e.getMessage());
723 }
724 String[] tmp = {ret.toString(),info};
725 return tmp;
726 }
727
728 /***
729 * Implementation of a unix-like 'tail' command
730 *
731 * @param aFileName a file name String
732 * @return An array of two strings is returned. At index 0 the String
733 * representation of at most 10 last lines is located.
734 * At index 1 there is an informational string about how large a
735 * segment of the file is being returned.
736 * Null is returned if errors occur (file not found or io exception)
737 */
738 public static String[] tail(String aFileName) {
739 return tail(aFileName, 10);
740 }
741
742 /***
743 * Implementation of a unix-like 'tail -n' command
744 *
745 * @param aFileName a file name String
746 * @param n int number of lines to be returned
747 * @return An array of two strings is returned. At index 0 the String
748 * representation of at most n last lines is located.
749 * At index 1 there is an informational string about how large a
750 * segment of the file is being returned.
751 * Null is returned if errors occur (file not found or io exception)
752 */
753 public static String[] tail(String aFileName, int n) {
754 try {
755 return tail(new RandomAccessFile(new File(aFileName),"r"),n);
756 } catch (FileNotFoundException e) {
757 e.printStackTrace();
758 return null;
759 }
760 }
761
762 /***
763 * Implementation of a unix-like 'tail -n' command
764 *
765 * @param raf a RandomAccessFile to tail
766 * @param n int number of lines to be returned
767 * @return An array of two strings is returned. At index 0 the String
768 * representation of at most n last lines is located.
769 * At index 1 there is an informational string about how large a
770 * segment of the file is being returned.
771 * Null is returned if errors occur (file not found or io exception)
772 */
773 public static String[] tail(RandomAccessFile raf, int n) {
774 int BUFFERSIZE = 1024;
775 long pos;
776 long endPos;
777 long lastPos;
778 int numOfLines = 0;
779 String info=null;
780 byte[] buffer = new byte[BUFFERSIZE];
781 StringBuffer sb = new StringBuffer();
782 try {
783 endPos = raf.length();
784 lastPos = endPos;
785
786
787
788 if (endPos > 0) {
789 byte[] oneByte = new byte[1];
790 raf.seek(endPos - 1);
791 raf.read(oneByte);
792 if ((char) oneByte[0] != '\n') {
793 numOfLines++;
794 }
795 }
796
797 do {
798
799
800 pos = 0;
801 if ((lastPos - BUFFERSIZE) > 0) {
802 pos = lastPos - BUFFERSIZE;
803 }
804 raf.seek(pos);
805
806 if ((lastPos - pos) < BUFFERSIZE) {
807 int remainer = (int) (lastPos - pos);
808 buffer = new byte[remainer];
809 }
810 raf.readFully(buffer);
811
812 for (int i = buffer.length - 1; i >= 0; i--) {
813 if ((char) buffer[i] == '\n') {
814 numOfLines++;
815
816 if (numOfLines > n) {
817 pos += (i + 1);
818 break;
819 }
820 }
821 }
822
823 lastPos = pos;
824 } while ((numOfLines <= n) && (pos != 0));
825
826
827 for (pos = lastPos; pos < endPos; pos += buffer.length) {
828 raf.seek(pos);
829 if ((endPos - pos) < BUFFERSIZE) {
830 int remainer = (int) (endPos - pos);
831 buffer = new byte[remainer];
832 }
833 raf.readFully(buffer);
834 sb.append(new String(buffer));
835 }
836
837 info = buildDisplayingHeader(sb.length(), raf.length());
838 } catch (FileNotFoundException e) {
839 sb = null;
840 } catch (IOException e) {
841 e.printStackTrace();
842 sb = null;
843 } finally {
844 try {
845 if (raf != null) {
846 raf.close();
847 }
848 } catch (IOException e) {
849 e.printStackTrace();
850 }
851 }
852 if(sb==null){
853 return null;
854 }
855 String[] tmp = {sb.toString(),info};
856 return tmp;
857 }
858
859 /***
860 * @param fileName
861 * @return
862 * @throws IOException
863 */
864 private static CompositeFileReader seriesReader(String fileName)
865 throws IOException {
866 LinkedList<File> filenames = new LinkedList<File>();
867 int seriesNumber = 1;
868 NumberFormat fmt = new DecimalFormat("00000");
869 String predecessorFilename =
870 fileName.substring(0,fileName.length()
871 - CrawlController.CURRENT_LOG_SUFFIX.length())
872 + fmt.format(seriesNumber);
873 while((new File(predecessorFilename)).exists()) {
874 filenames.add(new File(predecessorFilename));
875 seriesNumber++;
876 predecessorFilename =
877 fileName.substring(0,fileName.length()
878 - CrawlController.CURRENT_LOG_SUFFIX.length())
879 + fmt.format(seriesNumber);
880 }
881 filenames.add(new File(fileName));
882 return new CompositeFileReader(filenames);
883 }
884 }