Java:在不锁定文件的情况下打开和阅读文件

egdjgwm8  于 2023-01-01  发布在  Java
关注(0)|答案(4)|浏览(115)

我需要能够模仿'tail -f'与Java。我试图读取一个日志文件,因为它是由另一个进程写入,但当我打开文件读取它,它锁定文件和其他进程不能写了。任何帮助将不胜感激!
下面是我目前使用的代码:

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());
        }           
    }       
}
nbysray5

nbysray51#

由于一些特殊情况,如文件截断和(中间)删除,重建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创建一个尾巴,请参见:

请随意从代码中获取灵感,或者简单地复制您需要的部分。如果您发现任何我不知道的问题,请告诉我。

jv2fixgn

jv2fixgn2#

查看FileChannel API here。要锁定文件,可以选中here

7y4bm7vi

7y4bm7vi3#

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;
}
ccrfmcuu

ccrfmcuu4#

除非您在打开文件时指定了正确的共享标志,否则Windows将强制锁定文件。如果您要打开一个忙碌文件,则需要为Win32-API CreateFile指定一个带有共享标志FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE的句柄。
在JDK内部的一些地方,它被用来打开文件以阅读属性等,但据我所知,它没有被导出到Java类库级别,因此您需要找到一个本地库来完成此操作。
我认为作为一种快速解决方法,您可以从命令"cmd /D/C type file.lck"读取process.getInputStream()

相关问题