你如何在 Java 中连续读取文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2210975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you continuously read a file in Java?
提问by phill
I'm trying to figure out how to continuously read a file and once there is a new line added, output the line. I'm doing this using a sleep thread however it just seems to blow through the whole file and exit the program.
我想弄清楚如何连续读取文件,一旦添加了新行,就输出该行。我正在使用睡眠线程执行此操作,但是它似乎只是遍历整个文件并退出程序。
Any suggestions what I'm doing wrong?
任何建议我做错了什么?
Here is my code:
这是我的代码:
import java.io.*;
import java.lang.*;
import java.util.*;
class jtail {
public static void main (String args[])
throws InterruptedException, IOException{
BufferedReader br = new BufferedReader(
new FileReader("\\server01\data\CommissionPlanLog.txt"));
String line = null;
while (br.nextLine ) {
line = br.readLine();
if (line == null) {
//wait until there is more of the file for us to read
Thread.sleep(1000);
}
else {
System.out.println(line);
}
}
} //end main
} //end class jtail
thanks in advance
提前致谢
UPDATE: I've since changed the line "while (br.nextLine ) {" to just "while (TRUE) {"
更新:我已经将“while (br.nextLine) {”行更改为“while (TRUE) {”
回答by karoberts
This in somewhat old, but I have used the mechanism and it works pretty well.
这有点旧,但我已经使用了该机制并且效果很好。
edit: link no longer works, but I found it in the internet archive https://web.archive.org/web/20160510001134/http://www.informit.com/guides/content.aspx?g=java&seqNum=226
编辑:链接不再有效,但我在互联网档案中找到了它 https://web.archive.org/web/20160510001134/http://www.informit.com/guides/content.aspx?g=java&seqNum=226
The trick is to use a java.io.RandomAccessFile, and periodically check if the file length is greater that your current file position. If it is, then you read the data. When you hit the length, you wait. wash, rinse, repeat.
诀窍是使用java.io.RandomAccessFile, 并定期检查文件长度是否大于您当前的文件位置。如果是,那么您读取数据。当你达到长度时,你等待。清洗,冲洗,重复。
I copied the code, just in case that new link stops working
我复制了代码,以防万一新链接停止工作
package com.javasrc.tuning.agent.logfile;
import java.io.*;
import java.util.*;
/**
* A log file tailer is designed to monitor a log file and send notifications
* when new lines are added to the log file. This class has a notification
* strategy similar to a SAX parser: implement the LogFileTailerListener interface,
* create a LogFileTailer to tail your log file, add yourself as a listener, and
* start the LogFileTailer. It is your job to interpret the results, build meaningful
* sets of data, etc. This tailer simply fires notifications containing new log file lines,
* one at a time.
*/
public class LogFileTailer extends Thread
{
/**
* How frequently to check for file changes; defaults to 5 seconds
*/
private long sampleInterval = 5000;
/**
* The log file to tail
*/
private File logfile;
/**
* Defines whether the log file tailer should include the entire contents
* of the exising log file or tail from the end of the file when the tailer starts
*/
private boolean startAtBeginning = false;
/**
* Is the tailer currently tailing?
*/
private boolean tailing = false;
/**
* Set of listeners
*/
private Set listeners = new HashSet();
/**
* Creates a new log file tailer that tails an existing file and checks the file for
* updates every 5000ms
*/
public LogFileTailer( File file )
{
this.logfile = file;
}
/**
* Creates a new log file tailer
*
* @param file The file to tail
* @param sampleInterval How often to check for updates to the log file (default = 5000ms)
* @param startAtBeginning Should the tailer simply tail or should it process the entire
* file and continue tailing (true) or simply start tailing from the
* end of the file
*/
public LogFileTailer( File file, long sampleInterval, boolean startAtBeginning )
{
this.logfile = file;
this.sampleInterval = sampleInterval;
}
public void addLogFileTailerListener( LogFileTailerListener l )
{
this.listeners.add( l );
}
public void removeLogFileTailerListener( LogFileTailerListener l )
{
this.listeners.remove( l );
}
protected void fireNewLogFileLine( String line )
{
for( Iterator i=this.listeners.iterator(); i.hasNext(); )
{
LogFileTailerListener l = ( LogFileTailerListener )i.next();
l.newLogFileLine( line );
}
}
public void stopTailing()
{
this.tailing = false;
}
public void run()
{
// The file pointer keeps track of where we are in the file
long filePointer = 0;
// Determine start point
if( this.startAtBeginning )
{
filePointer = 0;
}
else
{
filePointer = this.logfile.length();
}
try
{
// Start tailing
this.tailing = true;
RandomAccessFile file = new RandomAccessFile( logfile, "r" );
while( this.tailing )
{
try
{
// Compare the length of the file to the file pointer
long fileLength = this.logfile.length();
if( fileLength < filePointer )
{
// Log file must have been rotated or deleted;
// reopen the file and reset the file pointer
file = new RandomAccessFile( logfile, "r" );
filePointer = 0;
}
if( fileLength > filePointer )
{
// There is data to read
file.seek( filePointer );
String line = file.readLine();
while( line != null )
{
this.fireNewLogFileLine( line );
line = file.readLine();
}
filePointer = file.getFilePointer();
}
// Sleep for the specified interval
sleep( this.sampleInterval );
}
catch( Exception e )
{
}
}
// Close the file that we are tailing
file.close();
}
catch( Exception e )
{
e.printStackTrace();
}
}
}
回答by Dan
If you're planning to implement this on a reasonable sized application where multiple objects might be interested in processing the new lines coming to the file, you might want to consider the Observerpattern.
如果您计划在一个合理大小的应用程序上实现这一点,其中多个对象可能对处理进入文件的新行感兴趣,您可能需要考虑观察者模式。
The object reading from the file will notify each object subscribed to it as soon as a line has been processed. This will allow you to keep logic well separated on the class where it's needed.
一旦处理了一行,从文件中读取的对象将通知每个订阅它的对象。这将允许您在需要的类中保持逻辑分离。
回答by kervin
Also consider org.apache.commons.io.input.Tailerif you do not have the requirement of writing this from scratch.
如果您没有从头开始编写的要求,也可以考虑org.apache.commons.io.input.Tailer。
回答by kervin
The way your code is written now, you will not go through your while loop when your 'line==null' because you are checking to see that it has a next line before you even get into the loop.
现在编写代码的方式,当你的 'line==null' 时你不会通过你的 while 循环,因为在你进入循环之前你正在检查它是否有下一行。
Instead, try doing a while(true){ }loop. That way, you will always be looping through it, catching your pause cases, until you hit a condition that would cause the program to end.
相反,尝试做一个while(true){ }循环。这样,您将始终循环遍历它,捕捉暂停情况,直到遇到导致程序结束的条件。

