题
我需要能够用 Java 模仿“tail -f”。我试图读取另一个进程正在写入的日志文件,但是当我打开文件来读取它时,它会锁定该文件,并且其他进程无法再写入它。任何帮助将不胜感激!
这是我当前正在使用的代码:
public void read(){
Scanner fp = null;
try{
fp = new Scanner(new FileReader(this.filename));
fp.useDelimiter("\n");
}catch(java.io.FileNotFoundException e){
System.out.println("java.io.FileNotFoundException e");
}
while(true){
if(fp.hasNext()){
this.parse(fp.next());
}
}
}
解决方案
由于一些特殊情况,例如文件截断和(中间)删除,重建 tail 很棘手。要在不锁定的情况下打开文件,请使用 StandardOpenOption.READ
使用新的 Java 文件 API,如下所示:
try (InputStream is = Files.newInputStream(path, StandardOpenOption.READ)) {
InputStreamReader reader = new InputStreamReader(is, fileEncoding);
BufferedReader lineReader = new BufferedReader(reader);
// Process all lines.
String line;
while ((line = lineReader.readLine()) != null) {
// Line content content is in variable line.
}
}
对于我在 Java 中创建尾部的尝试,请参阅:
- 方法
examineFile(…)
在 https://github.com/AugustusKling/yield/blob/master/src/main/java/yield/input/file/FileMonitor.java - 以上使用的是 https://github.com/AugustusKling/yield/blob/master/src/main/java/yield/input/file/FileInput.java 创建尾部操作。这
queue.feed(lineContent)
传递行内容供听众处理,并且等于您的this.parse(…)
.
请随意从该代码中获取灵感或直接复制您需要的部分。如果您发现任何我不知道的问题,请告诉我。
其他提示
java.io给你一个强制性文件锁和java.nio中给你一个 咨询文件锁
如果您想阅读文件,而您可以使用下面的类的任何锁
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
如果你想通过尾下面代码线用于同一
一个文件中的行public void tail(String logPath){
String logStr = null;
FileChannel fc = null;
try {
fc = FileChannel.open(Paths.get(logPath), StandardOpenOption.READ);
fc.position(fc.size());
} catch (FileNotFoundException e1) {
System.out.println("FileNotFoundException occurred in Thread : " + Thread.currentThread().getName());
return;
} catch (IOException e) {
System.out.println("IOException occurred while opening FileChannel in Thread : " + Thread.currentThread().getName());
}
while (true) {
try {
logStr = readLine(fc);
if (logStr != null) {
System.out.println(logStr);
} else {
Thread.sleep(1000);
}
} catch (IOException|InterruptedException e) {
System.out.println("Exception occurred in Thread : " + Thread.currentThread().getName());
try {
fc.close();
} catch (IOException e1) {
}
break;
}
}
}
private String readLine(FileChannel fc) throws IOException {
ByteBuffer buffers = ByteBuffer.allocate(128);
// Standard size of a line assumed to be 128 bytes
long lastPos = fc.position();
if (fc.read(buffers) > 0) {
byte[] data = buffers.array();
boolean foundTmpTerminator = false;
boolean foundTerminator = false;
long endPosition = 0;
for (byte nextByte : data) {
endPosition++;
switch (nextByte) {
case -1:
foundTerminator = true;
break;
case (byte) '\r':
foundTmpTerminator = true;
break;
case (byte) '\n':
foundTmpTerminator = true;
break;
default:
if (foundTmpTerminator) {
endPosition--;
foundTerminator = true;
}
}
if (foundTerminator) {
break;
}
}
fc.position(lastPos + endPosition);
if (foundTerminator) {
return new String(data, 0, (int) endPosition);
} else {
return new String(data, 0, (int) endPosition) + readLine(fc);
}
}
return null;
}
Windows使用的文件强制锁定,除非你,而你打开指定权份额标志。如果你想打开一个繁忙的文件,你需要Win32的API CreateFile
一个手柄与共享标记FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE
。
这是使用JDK里面的几个地方打开的文件读取属性之类的东西,但据我可以看到它不会导出/可用于Java类库的水平。所以,你需要找到一个本地库来做到这一点。
我觉得作为一个快速的解决办法,你可以阅读从命令process.getInputStream()
"cmd /D/C type file.lck"
不隶属于 StackOverflow