如何使用Java从正在写入的文件读取?
我有一个将信息写入文件的应用程序。 此信息在执行后用于确定应用程序的通过/失败/正确性。 我希望能够在正在写入的文件中读取文件,以便我可以实时进行这些通过/失败/正确性检查。
我认为有可能做到这一点,但使用Java时涉及的问题是什么? 如果读取到达写入,是否等待更多的写入,直到文件closures,或读取会在此时抛出exception? 如果是后者,那么我该怎么办?
我的直觉是目前推动我BufferedStreams。 这是要走的路吗?
无法获得使用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。 是的,我知道我还在石器时代。
看看从Apache Commons IO使用Tailer 。 它处理大多数边缘情况。
你也可以看看java通道来locking文件的一部分。
http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html
FileChannel
这个function可能是一个开始
lock(long position, long size, boolean shared)
此方法的调用会阻塞,直到该区域可被locking
如果您要在写入文件的同时读取文件,只读取新内容,那么以下内容将帮助您达到相同效果。
要运行此程序,您将从命令提示符/terminal窗口启动它并传递文件名称以进行读取。 它会读取文件,除非你杀了程序。
java FileReader c:\ myfile.txt
当你input一行文本从记事本保存它,你会看到在控制台中打印的文本。
public class FileReader { public static void main(String args[]) throws Exception { if(args.length>0){ File file = new File(args[0]); System.out.println(file.getAbsolutePath()); if(file.exists() && file.canRead()){ long fileLength = file.length(); readFile(file,0L); while(true){ if(fileLength<file.length()){ readFile(file,fileLength); fileLength=file.length(); } } } }else{ System.out.println("no file to read"); } } public static void readFile(File file,Long fileLength) throws IOException { String line = null; BufferedReader in = new BufferedReader(new java.io.FileReader(file)); in.skip(fileLength); while((line = in.readLine()) != null) { System.out.println(line); } in.close(); } }
我完全同意约书亚的回应 , 泰勒适合在这种情况下工作。 这里是一个例子:
它每150毫秒在一个文件中写一行,而每2500毫秒读一次这个相同的文件
public class TailerTest { public static void main(String[] args) { File f = new File("/tmp/test.txt"); MyListener listener = new MyListener(); Tailer.create(f, listener, 2500); try { FileOutputStream fos = new FileOutputStream(f); int i = 0; while (i < 200) { fos.write(("test" + ++i + "\n").getBytes()); Thread.sleep(150); } fos.close(); } catch (Exception e) { e.printStackTrace(); } } private static class MyListener extends TailerListenerAdapter { @Override public void handle(String line) { System.out.println(line); } } }
答案似乎是“不”……和“是”。 似乎没有真正的方法来知道一个文件是否被另一个应用程序写入。 所以,从这样的文件中读取只会进行到内容耗尽。 我采取了迈克的build议,并写了一些testing代码:
Writer.java将一个string写入文件,然后等待用户在将另一行写入文件之前按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); } }
不保证此代码是最佳实践。
这留下Mikebuild议的选项,定期检查是否有新的数据从文件中读取。 然后,当确定读取完成时,这需要用户介入来closures文件读取器。 或者,读者需要了解文件的内容,并能够确定和结束写入条件。 如果内容是XML,则可以使用文档的结尾来发信号。
不是Java本身,但是你可能碰到你写了一些东西到文件的问题,但是它还没有真正写入 – 它可能在某个地方的某个caching中,而从同一个文件中读取可能实际上不会给你新的信息。
短版本 – 使用flush()或任何相关的系统调用来确保您的数据实际写入文件。
注意我不是在谈论操作系统级的磁盘caching – 如果你的数据进入这里,它应该出现在read()之后。 这可能是语言本身caching写入,等待缓冲区填满或文件被刷新/closures。
有一个开源的Javagraphics尾巴,这样做。
https://stackoverflow.com/a/559146/1255493
public void run() { try { while (_running) { Thread.sleep(_updateInterval); long len = _file.length(); if (len < _filePointer) { // Log must have been jibbled or deleted. this.appendMessage("Log file was reset. Restarting logging from start of file."); _filePointer = len; } else if (len > _filePointer) { // File must have had something added to it! RandomAccessFile raf = new RandomAccessFile(_file, "r"); raf.seek(_filePointer); String line = null; while ((line = raf.readLine()) != null) { this.appendLine(line); } _filePointer = raf.getFilePointer(); raf.close(); } } } catch (Exception e) { this.appendMessage("Fatal error reading log file, log tailing has stopped."); } // dispose(); }
我从来没有尝试过,但是你应该编写一个testing用例,看看在结束后读取数据stream是否有效,不pipe是否有更多的数据写入文件。
有没有理由不能使用pipe道input/输出stream? 数据是从同一个应用程序写入和读取的(如果是这样,你有数据,为什么你需要从文件中读取)?
否则,可能会读到文件结尾,然后监视变化,并寻求你离开的地方继续…但要注意比赛条件。
您无法读取使用FileInputStream,FileReader或RandomAccessFile从另一个进程打开的文件。
但直接使用FileChannel将工作:
private static byte[] readSharedFile(File file) throws IOException { byte buffer[] = new byte[(int) file.length()]; final FileChannel fc = FileChannel.open(file.toPath(), EnumSet.of(StandardOpenOption.READ)); final ByteBuffer dst = ByteBuffer.wrap(buffer); fc.read(dst); fc.close(); return buffer; }