如何检查正在使用java进行外部更新的文件的内容?
有一个shell脚本正在更新日志文件 我想在日志文件写入时逐行显示日志(而不是一次显示整个文件) 写入文件工作正常,但我在读取文件时遇到问题,因为它一次显示整个文件 以下是我的阅读代码:如何检查正在使用java进行外部更新的文件的内容?,java,file-io,process,Java,File Io,Process,有一个shell脚本正在更新日志文件 我想在日志文件写入时逐行显示日志(而不是一次显示整个文件) 写入文件工作正常,但我在读取文件时遇到问题,因为它一次显示整个文件 以下是我的阅读代码: String nmapstatusfile = runMT.instdir+"/logs/nmapout."+customer+".log"; String nmapcommand=runMT.instdir+"/bin/doscan.sh "+nmapoutfile+" " +IPRange+" "+
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,但无法获得所需的结果
如何读取文件内容以便逐行显示
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter(new File("C://test.txt"));
BufferedWriter bw = new BufferedWriter(fw);
bw.append("Hi");
//bw.close();
FileReader fr = new FileReader(new File("C://test.txt"));
BufferedReader br = new BufferedReader(fr);
System.out.println(br.readLine());
}
OP : null
if you uncomment bw.close() , then OP : Hi..
所以,问题是每次脚本写入日志文件时,都需要保存该文件,需要通知()等待的线程,并在控制台上显示它 您可以为读卡器实现轮询策略,以避免从写卡器向读卡器发送额外通知
下面是一个简单的工作示例:
- Writer从主线程更新日志文件(通过控制台的用户输入)
- 读卡器定期轮询
,并输出一行日志文件
当多个读写器在不同的线程/进程中运行时,您可能需要添加额外的文件锁定和一致性检查。这需要Java 7,因为它在文件系统上注册了一个监视程序,当给定文件发生更改时,将通知该监视程序。它允许任意数量的读卡器(使用同步来避免竞争条件)
所以你的意思是说如果你的脚本在文件中写了一行,你的程序必须在控制台上显示它???看看这个。可能重复我不知道你为什么坚持在这里使用递归。这真的是问题的一部分吗?@KickButtowski,因为我认为实际的问题是关于IO操作,而不是算法(无论是递归还是简单迭代)。unix和windows下的文件系统语义不同。我很确定OP正在使用unix(“.sh”文件终止),而您似乎正在使用windows。@tucuxi-是的。。他正在使用shell脚本:)。。。这将如何改变OP在读取日志文件之前必须保存日志文件的事实(我相信他希望逐行读取)。。我只是指出他可能面临的问题。。。他已经开始写shell脚本了。。它正在异步运行。。。现在,他怎么知道什么时候该读书??。。他无法控制写入日志文件的数据。如果我错了,请纠正我。。。。脚本只有在完成将所有内容写入文件时才会关闭该文件。在windows中,读取尚未关闭的文件通常是错误的。在unix中,这样做是非常典型的,根本不是错误。OP试图用unix的方式做事情(本质上实现了一种“tail-f”)。噢。。正在重定向O/P。。。看起来很公平。。。但他说“我希望递归地显示日志文件中的日志。这意味着当脚本在日志文件中写入时,我希望读取文件的内容并逐行显示”。。他不希望流/重定向O/P。。。他想直接从日志文件中读取。。当它被其他线程写入时,如何能够读取它???请参见下面我的答案。在linux下工作正常-在一个控制台上附加到文件,请参阅正在运行的程序显示更改。
public class Test {
public static void main(String[] args) throws IOException {
// async log reader based on timerTask
LogReader logReader = new LogReader("test.txt");
logReader.start(); // starts polling log file in Timer thread
// main thread simulating writes to file from user input
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter logWriter = new BufferedWriter(new FileWriter(new File("test.txt")));
String line = null;
while (!(line = console.readLine()).equals("end")) {
logWriter.write(line);
logWriter.newLine();
logWriter.flush();
}
logReader.stop();
logWriter.close();
}
/**
* reads file from separate thread
*/
static class LogReader {
File mLogFile = null;
BufferedReader mReader = null;
TimerTask mCheckFileTask = null;
LogReader(String logFile) throws FileNotFoundException {
mLogFile = new File(logFile);
mReader = new BufferedReader(new FileReader(mLogFile));
}
/**
* launches checking thread and output thread
*/
void start() {
mCheckFileTask = new TimerTask() {
@Override
public void run() {
// possibly some extra checks :
// file size or lastModified() time changed since last time
try {
writeChange();
} catch (IOException e1) {
e1.printStackTrace();
throw new Error(e1);
}
}
};
new Timer().schedule(mCheckFileTask, 500, 500);
}
private void writeChange() throws IOException {
String line;
line = mReader.readLine();
if (line != null) {
System.out.println("line added: " + line);
}
}
void stop() throws IOException {
System.out.println("stopping reader");
mCheckFileTask.cancel();
mReader.close();
}
}
}
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);
}
}
}