打开并读取文件而不锁定它

问题描述 投票:0回答:4

我需要能够用 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());
        }           
    }       
}
java java-io file-locking
4个回答
12
投票

由于文件截断和(中间)删除等特殊情况,重建 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 中创建尾部的尝试,请参阅:

  • https://github.com/AugustusKling/yield/blob/master/src/main/java/yield/input/file/FileMonitor.java中的方法
    examineFile(…)
  • 以上内容由
  • https://github.com/AugustusKling/yield/blob/master/src/main/java/yield/input/file/FileInput.java 使用来创建尾部操作。 queue.feed(lineContent)
     传递行内容供听众处理,并且等于您的 
    this.parse(…)
您可以随意从该代码中获取灵感,或者直接复制您需要的部分。如果您发现任何我不知道的问题,请告诉我。


2
投票
查看 FileChannel API

此处。要锁定文件,您可以检查此处


2
投票
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; }
    

0
投票
Windows 对文件使用强制锁定,除非您在打开时指定正确的共享标志。如果您想打开一个繁忙的文件,您需要 Win32-API

CreateFile

 带有共享标志 
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE
 的句柄。

这在 JDK 内部的一些地方用于打开文件以读取属性和内容,但据我所知,它没有导出/可用到 Java 类库级别。所以你需要找到一个本地库来做到这一点。

我认为作为一种快速解决方法,您可以从命令

process.getInputStream()

 中读取 
"cmd /D/C type file.lck"

© www.soinside.com 2019 - 2024. All rights reserved.