Java: открытие и чтение из файла без его блокировки - PullRequest
10 голосов
/ 29 марта 2010

Мне нужно иметь возможность имитировать '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());
        }           
    }       
}

Ответы [ 4 ]

6 голосов
/ 12 ноября 2014

Перестроить хвост сложно из-за некоторых особых случаев, таких как усечение файла и (промежуточное) удаление. Чтобы открыть файл без блокировки, используйте StandardOpenOption.READ с новым API-интерфейсом Java-файлов, например:

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 см .:

Не стесняйтесь черпать вдохновение из этого кода или просто скопируйте нужные вам части. Дайте мне знать, если вы обнаружите какие-либо проблемы, о которых я не знаю.

1 голос
/ 22 ноября 2018

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;
}
1 голос
/ 29 марта 2010

Посмотрите на FileChannel API здесь . Для блокировки файла вы можете проверить здесь

0 голосов
/ 12 ноября 2014

Windows использует обязательную блокировку для файлов, если вы не укажете нужные флаги общего доступа при открытии. Если вы хотите открыть занятой файл, вам нужно Win32-API CreateFile дескриптор с флагами общего доступа FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE.

Это используется внутри JDK в нескольких местах, чтобы открывать файлы для чтения атрибутов и прочего, но, насколько я вижу, он не экспортируется / не доступен для уровня библиотеки классов Java. Так что для этого вам нужно найти нативную библиотеку.

Я думаю, что для быстрого обхода вы можете прочитать process.getInputStream() из команды "cmd /D/C type file.lck"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...