Como posso bloquear um arquivo usando java (se possível)

Eu tenho um processo Java que abre um arquivo usando um FileReader. Como posso impedir que outro processo (Java) abra esse arquivo ou, pelo menos, notifique esse segundo processo de que o arquivo já está aberto? Isso faz automaticamente o segundo processo obter uma exceção se o arquivo estiver aberto (o que resolve meu problema) ou eu tenho que explicitamente abri-lo no primeiro processo com algum tipo de sinalizador ou argumento?

Esclarecer:

Eu tenho um aplicativo Java que lista uma pasta e abre cada arquivo na listview para processá-lo. Ele processa cada arquivo após o outro. O processamento de cada arquivo consiste em lê-lo e fazer alguns cálculos com base no conteúdo e leva cerca de 2 minutos. Eu também tenho outro aplicativo Java que faz a mesma coisa, mas escreve no arquivo. O que eu quero é poder rodar esses aplicativos ao mesmo tempo, então o cenário é assim. ReadApp lista a pasta e encontra os arquivos A, B, C. Ela abre o arquivo A e inicia a leitura. WriteApp lista a pasta e localiza os arquivos A, B, C. Ela abre o arquivo A, vê que está aberto (por uma exceção ou qualquer outra forma) e vai para o arquivo B. ReadApp conclui o arquivo A e continua para B. Ele o vê está aberto e continua em C. É crucial que WriteApp não escreva enquanto o ReadApp estiver lendo o mesmo arquivo ou vice-versa. Eles são processos diferentes.

FileChannel.lock é provavelmente o que você deseja.

FileInputStream in = new FileInputStream(file); try { java.nio.channels.FileLock lock = in.getChannel().lock(); try { Reader reader = new InputStreamReader(in, charset); ... } finally { lock.release(); } } finally { in.close(); } 

(Aviso: Código não compilado e certamente não testado.)

Observe a seção intitulada “dependencies da plataforma” no documento da API do FileLock .

Não use as classs no pacote java.io , em vez disso, use o pacote java.nio . Este último tem uma class FileLock . Você pode aplicar um bloqueio a um FileChannel .

  try { // Get a file channel for the file File file = new File("filename"); FileChannel channel = new RandomAccessFile(file, "rw").getChannel(); // Use the file channel to create a lock on the file. // This method blocks until it can retrieve the lock. FileLock lock = channel.lock(); /* use channel.lock OR channel.tryLock(); */ // Try acquiring the lock without blocking. This method returns // null or throws an exception if the file is already locked. try { lock = channel.tryLock(); } catch (OverlappingFileLockException e) { // File is already locked in this thread or virtual machine } // Release the lock - if it is not null! if( lock != null ) { lock.release(); } // Close the file channel.close(); } catch (Exception e) { } 

Se você pode usar o Java NIO ( JDK 1.4 ou superior ), então eu acho que você está procurando por java.nio.channels.FileChannel.lock()

FileChannel.lock ()

use java.nio.channels.FileLock em conjunto com java.nio.channels.FileChannel

Isso pode não ser o que você está procurando, mas no interesse de chegar a um problema de outro ângulo ….

Esses dois processos Java podem querer acessar o mesmo arquivo no mesmo aplicativo? Talvez você possa filtrar todo o access ao arquivo através de um único método sincronizado (ou, melhor ainda, usando o JSR-166 )? Dessa forma, você pode controlar o access ao arquivo e talvez até enfileirar solicitações de access.

Use um RandomAccessFile, pegue seu canal e chame lock (). O canal fornecido pelos streams de input ou saída não tem privilégios suficientes para bloquear adequadamente. Certifique-se de chamar unlock () no bloco finally (o fechamento do arquivo não necessariamente libera o bloqueio).

Eu encontrei o mesmo problema alguns anos atrás, quando eu escrevi um aplicativo que exigia vários usuários no MacOS / Windows para compartilhar os mesmos dados em vários arquivos. O bloqueio de arquivos não funcionou no MacOS, então eu criei minha própria class ‘ioFile’, que mantinha seu próprio registro de access a arquivos – open r / o, open r / w, etc, e quem ‘possuía’ o bloqueio. Esta é a única maneira, na época, de controlar o access de diferentes usuários em diferentes máquinas, usando sistemas operacionais diferentes.

Abaixo está um código de fragment de amostra para bloquear um arquivo até que o processo seja executado pela JVM.

  public static void main(String[] args) throws InterruptedException { File file = new File(FILE_FULL_PATH_NAME); RandomAccessFile in = null; try { in = new RandomAccessFile(file, "rw"); FileLock lock = in.getChannel().lock(); try { while (in.read() != -1) { System.out.println(in.readLine()); } } finally { lock.release(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } 

Se você colocar o access ao arquivo no bloco sincronizado, apenas uma instância do thread poderá entrar nele, outras aguardarão, até que uma delas termine o trabalho.

 public class FileReader{ public void read() { synchronized (this) { //put you file access here } } } 
 package tips.javabeat.nio.lock; import java.io.*; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; public class FileLockTest { public static void main(String[] args) throws Exception { RandomAccessFile file = null; FileLock fileLock = null; try { file = new RandomAccessFile("FileToBeLocked", "rw"); FileChannel fileChannel = file.getChannel(); fileLock = fileChannel.tryLock(); if (fileLock != null){ System.out.println("File is locked"); accessTheLockedFile(); } }finally{ if (fileLock != null){ fileLock.release(); } } } static void accessTheLockedFile(){ try{ FileInputStream input = new FileInputStream("FileToBeLocked"); int data = input.read(); System.out.println(data); }catch (Exception exception){ exception.printStackTrace(); } } 

Você usa APIs java.nio. * Para bloquear um arquivo. No entanto, isso não garante o bloqueio. Depende se o SO subjacente suporta o bloqueio ou não. Pelo que entendi Sistemas operacionais como o Linux não suportam bloqueio e, portanto, você não pode bloquear, mesmo se você usar essas APIs