Java: abrindo e lendo um arquivo sem travá -lo
Pergunta
Eu preciso ser capaz de imitar a 'cauda' com Java. Estou tentando ler um arquivo de log como está sendo escrito por outro processo, mas quando abro o arquivo para lê -lo, ele bloqueia o arquivo e o outro processo não pode mais gravar nele. Qualquer ajuda seria muito apreciada!
Aqui está o código que estou usando atualmente:
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());
}
}
}
Solução
A cauda de reconstrução é complicada devido a alguns casos especiais, como truncamento de arquivos e exclusão (intermediária). Para abrir o arquivo sem travar o uso StandardOpenOption.READ
com a nova API de arquivo java como assim:
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.
}
}
Para minha tentativa de criar uma cauda em Java, consulte:
- Método
examineFile(…)
dentro https://github.com/augustuskling/yield/blob/master/src/main/java/yield/input/file/filemonitor.java - O acima é usado por https://github.com/augustuskling/yield/blob/master/src/main/java/yield/input/file/fileinput.java Para criar uma operação de cauda. o
queue.feed(lineContent)
passa o conteúdo da linha para processamento dos ouvintes e seria igual ao seuthis.parse(…)
.
Sinta -se à vontade para inspirar -se nesse código ou simplesmente copiar as peças necessárias. Deixe -me saber se você encontrar algum problema que eu não esteja ciente.
Outras dicas
java.io fornece um bloqueio de arquivo obrigatório e java.nio oferece um bloqueio de arquivo consultivo
Se você quiser ler qualquer arquivo sem bloqueio, você pode usar abaixo as aulas
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
Se você deseja atingir uma linha de arquivo por linha, use abaixo o código para o mesmo
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;
}
O Windows usa bloqueio obrigatório para arquivos, a menos que você especifique os sinalizadores de compartilhamento certos enquanto você abre. Se você deseja abrir um arquivo ocupado, precisa Win32-api CreateFile
uma alça com as bandeiras de compartilhamento FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE
.
Isso é usado dentro do JDK em alguns lugares para abrir arquivos para leitura de atributos e outras coisas, mas até onde eu posso ver que não está exportado/disponível para o nível da biblioteca de classes Java. Então você precisaria encontrar uma biblioteca nativa para fazer isso.
Eu acho que como um trabalho rápido ao seu redor pode ler process.getInputStream()
do comando "cmd /D/C type file.lck"