如何使用Java读取正在被主动写入的文件?
我有一个将信息写入文件的应用程序。该信息在执行后用于确定应用程序的通过/失败/正确性。我希望能够在写入文件时读取它,以便可以实时进行通过/失败/正确性检查。
我认为可以做到这一点,但是使用Java时所涉及的陷阱是什么?如果阅读赶上了写作,它会只是等待更多的写操作直到文件关闭,还是此时读将引发异常?如果是后者,我该怎么办?
我的直觉目前将我推向BufferedStreams。这是要走的路吗?
解决方案
回答
不是Java本身,但是我们可能会遇到这样的问题,即我们已经向文件中写入了一些内容,但实际上尚未写入,但它可能位于某个地方的高速缓存中,并且从同一文件中读取内容实际上可能不会给我们带来好处。新讯息。
短版使用flush()或者任何相关的系统调用来确保数据实际上已写入文件中。
注意如果数据进入这里,我并不是在谈论操作系统级别的磁盘缓存,此后它应该出现在read()中。语言本身可能会缓存写操作,等待缓冲区填满或者刷新/关闭文件。
回答
我从未尝试过,但是我们应该编写一个测试用例,以查看在结束后从流中读取是否可以工作,而不管是否有更多数据写入该文件。
我们有理由不能使用管道输入/输出流吗?是否正在从同一应用程序中写入和读取数据(如果有,我们拥有数据,为什么需要从文件中读取数据)?
否则,可能要读到文件末尾,然后监视更改并寻找到上次停止的地方并继续...尽管要注意比赛条件。
回答
答案似乎是"否"和"是"。似乎没有真正的方法知道文件是否已打开以供其他应用程序写入。因此,从此类文件读取将一直进行到内容耗尽为止。我接受了Mike的建议,并编写了一些测试代码:
Writer.java将字符串写入文件,然后等待用户按下Enter键,然后再将另一行写入文件。其想法是可以启动它,然后可以开始阅读器以查看它如何处理"部分"文件。我写的读者在Reader.java中。
Writer.java
public class Writer extends Object { Writer () { } public static String[] strings = { "Hello World", "Goodbye World" }; public static void main(String[] args) throws java.io.IOException { java.io.PrintWriter pw = new java.io.PrintWriter(new java.io.FileOutputStream("out.txt"), true); for(String s : strings) { pw.println(s); System.in.read(); } pw.close(); } }
Reader.java
public class Reader extends Object { Reader () { } public static void main(String[] args) throws Exception { java.io.FileInputStream in = new java.io.FileInputStream("out.txt"); java.nio.channels.FileChannel fc = in.getChannel(); java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocate(10); while(fc.read(bb) >= 0) { bb.flip(); while(bb.hasRemaining()) { System.out.println((char)bb.get()); } bb.clear(); } System.exit(0); } }
不能保证此代码是最佳实践。
这使Mike建议我们选择定期检查是否有新数据要从文件中读取的选项。然后,当确定读取已完成时,这需要用户干预以关闭文件读取器。或者,需要使读者知道文件的内容,并能够确定和结束写入条件。如果内容是XML,则可以使用文档末尾的信号。
回答
我们还可以查看用于锁定文件一部分的java通道。
http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html
FileChannel的此功能可能是一个开始
lock(long position, long size, boolean shared)
对该方法的调用将阻塞,直到可以锁定该区域为止
回答
无法使用示例使用FileChannel.read(ByteBuffer),因为它不是阻塞读取。但是没有让下面的代码正常工作吗:
boolean running = true; BufferedInputStream reader = new BufferedInputStream(new FileInputStream( "out.txt" ) ); public void run() { while( running ) { if( reader.available() > 0 ) { System.out.print( (char)reader.read() ); } else { try { sleep( 500 ); } catch( InterruptedException ex ) { running = false; } } } }
当然,相同的东西可以用作计时器而不是线程,但是我将其留给程序员。我仍在寻找一种更好的方法,但这目前对我有效。
哦,我要警告一下:我正在使用1.4.2. 是的,我知道我还在石器时代。