Java - Язык:открытие и чтение из файла без его блокировки
Вопрос
Мне нужно иметь возможность имитировать '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());
}
}
}
Решение
Перестроить хвост сложно из-за некоторых особых случаев, таких как усечение файла и (промежуточное) удаление.Чтобы открыть файл без блокировки, используйте StandardOpenOption.READ
с новым Java file 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.
}
}
О моей попытке создать tail в 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"