Vis*_*was 2 java file-io process
有一个 shell 脚本正在更新日志文件。
我想在写入日志文件时逐行显示日志(而不是一次显示整个文件)。
写入文件工作正常,但我在读取文件时遇到问题,因为它一次显示整个文件。
这是我的阅读代码:
String nmapstatusfile = runMT.instdir+"/logs/nmapout."+customer+".log";
String nmapcommand=runMT.instdir+"/bin/doscan.sh "+nmapoutfile+" "
    +IPRange+" "+nmapstatusfile+" "+nmapdonefile;
System.out.println("nmapcommand is .. "+nmapcommand);
Runtime r = Runtime.getRuntime();
Process pr = r.exec(nmapcommand);
RandomAccessFile raf =null;
try {
    System.out.println(nmapstatusfile);
    System.out.println("Reading a file");
raf = new RandomAccessFile(nmapstatusfile, "r");            
} catch (FileNotFoundException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
} // read from input file
System.out.println("Will print file contents line by line...");
long pos = 0;
raf.seek(pos);
String line =null;
while ((line = raf.readLine())!= null) {
    System.out.println("in while loop for file read.");
    System.out.println(line);
}
pos = raf.getFilePointer();
pr.waitFor();   
我已经使用了 RandomAccessFile,但是一直无法得到想要的结果。
我应该如何读取文件内容以便逐行显示?
这需要 Java 7,因为它在文件系统上注册了一个观察者,每当给定的文件发生变化时都会收到通知。它允许任意数量的读取器(使用同步来避免竞争条件)。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayDeque;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * Reads lines from a file that is actively being updated by another process
 */
public class Tailer {
    private static final Logger logger = Logger.getLogger("Tailer");
    private long tooLateTime = -1;
    private final long maxMsToWait;
    private final File file;
    private long offset = 0;
    private int lineCount = 0;
    private boolean ended = false;
    private WatchService watchService = null; 
    ArrayDeque<String> lines = new ArrayDeque<>();
    /**
     * Allows output of a file that is being updated by another process.
     * @param file to watch and read
     * @param maxTimeToWaitInSeconds max timeout; after this long without changes,
     * watching will stop. If =0, watch will continue until <code>stop()</code>
     * is called.
     */
    public Tailer(File file, long maxTimeToWaitInSeconds) {
        this.file = file;
        this.maxMsToWait = maxTimeToWaitInSeconds * 1000;
    }
    /**
     * Start watch.
     */
    public void start() {
        updateOffset();
        // listens for FS events
        new Thread(new FileWatcher()).start();  
        if (maxMsToWait != 0) {
            // kills FS event listener after timeout
            new Thread(new WatchDog()).start();
        }     
    }
    /**
     * Stop watch.
     */
    public void stop() {
        if (watchService != null) {
            try {
                watchService.close();
            } catch (IOException ex) {
                logger.info("Error closing watch service");
            }
            watchService = null;
        }
    }
    private synchronized void updateOffset() {
        tooLateTime = System.currentTimeMillis() + maxMsToWait;
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            br.skip(offset);            
            while (true) {
                String line = br.readLine();
                if (line != null) {
                    lines.push(line);
                    // this may need tweaking if >1 line terminator char
                    offset += line.length() + 1; 
                } else {
                    break;
                }
            }
            br.close();
        } catch (Exception ex) {
            logger.log(Level.SEVERE, "Error reading", ex);
        }        
    }
    /**
     * @return true if lines are available to read
     */
    public boolean linesAvailable() {
        return ! lines.isEmpty();
    }
    /**
     * @return next unread line
     */
    public synchronized String getLine() {
        if (lines.isEmpty()) {
            return null;
        } else {
            lineCount ++;
            return lines.removeLast();
        }
    }
    /**
     * @return true if no more lines will ever be available, 
     * because stop() has been called or the timeout has expired
     */
    public boolean hasEnded() {
        return ended;
    }
    /**
     * @return next line that will be returned; zero-based
     */
    public int getLineNumber() {
        return lineCount;
    }
    private class WatchDog implements Runnable {
        @Override
        public void run() {
            while (System.currentTimeMillis() < tooLateTime) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    // do nothing
                }
            }
            stop();
        }
    }
    private class FileWatcher implements Runnable {
        private final Path path = file.toPath().getParent();
        @Override
        public void run() {
            try {
                watchService = path.getFileSystem().newWatchService();
                path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
                while (true) {
                    WatchKey watchKey = watchService.take();
                    if ( ! watchKey.reset()) {
                        stop();
                        break;
                    } else if (! watchKey.pollEvents().isEmpty()) {
                        updateOffset();
                    }
                    Thread.sleep(500);
                }
            } catch (InterruptedException ex) {
                logger.info("Tail interrupted");
            } catch (IOException ex) {
                logger.log(Level.WARNING, "Tail failed", ex);
            } catch (ClosedWatchServiceException ex) {
                // no warning required - this was a call to stop()
            }
            ended = true;
        }
    }
    /**
     * Example main. Beware: the watch listens on a whole folder, not on a single
     * file. Any update on a file within the folder will trigger a read-update.
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        String fn = args.length == 0 ? "/tmp/test/log.txt" : args[0];
        Tailer t = new Tailer(new File(fn), 10);
        t.start();
        while ( ! t.hasEnded()) {
            while (t.linesAvailable()) {
                System.out.println(t.getLineNumber() + ": " + t.getLine());
            }
            Thread.sleep(500);
        }
    }
}
| 归档时间: | 
 | 
| 查看次数: | 1897 次 | 
| 最近记录: |