Como verificar se o arquivo está sendo gravado antes de tentar processá-lo?

Difícil dar um bom título ao meu problema, mas é o seguinte. Primeiro, estou fazendo isso no Windows e ele pode ser usado em uma checkbox Linux também, então eu precisaria da correção para trabalhar em ambos os sistemas. Estou monitorando um diretório para novos arquivos. Eu basicamente olhando os arquivos do diretório e comparando-os repetidas vezes e apenas processando os novos arquivos. Problema é que eu continuo recebendo um erro onde o arquivo não está acabado de ser escrito antes de tentar processar.

public class LiveDetectionsProvider extends DetectionsProvider { protected LiveDetectionsProvider.MonitorDirectory monitorDirectory = null; protected TimeModel timeModel = null; private ArrayList loaded = new ArrayList(); private File topLayerFolder = null; public LiveDetectionsProvider(String directory, String id) { super(directory, id); timeModel = super.timeModel; } /** * Initialize the data provider. */ public void initialize() { try { topLayerFolder = new File(directory); File[] dir = topLayerFolder.listFiles(); for (File file : dir) { loaded.add(file.getName()); } monitorDirectory = new MonitorDirectory(); monitorDirectory.execute(); } catch (Exception ex) { Logger.getLogger(LiveDetectionsProvider.class.getName()).log(Level.SEVERE, "Failed to read detection\n{0}", ex.getMessage()); } super.initialize(); } /** * Un-initialize the data provider. */ public void uninitialize() { super.uninitialize(); if (monitorDirectory != null) { monitorDirectory.continuing = false; } } /** * The class that is used to load the detection points in a background * thread. */ protected class MonitorDirectory extends SwingWorker { public boolean continuing = true; /** * The executor service thread pool. */ private ExecutorService executor = null; /** * The completion service that reports the completed threads. */ private CompletionService completionService = null; @Override protected Void doInBackground() throws Exception { int count = 0; executor = Executors.newFixedThreadPool(1); completionService = new ExecutorCompletionService(executor); while (continuing && topLayerFolder != null) { File[] dir = topLayerFolder.listFiles(); Thread.sleep(10); ArrayList filesToLoad = new ArrayList(); for (File file : dir) { if (!loaded.contains(file.getName())) { long filesize = 0; boolean cont = true; while (cont) { if (file.length() == filesize) { cont = false; Thread.sleep(3); filesToLoad.add(file); } else { filesize = file.length(); Thread.sleep(3); } } Thread.sleep(3); } } for (File file : filesToLoad) { timeModel.setLoadingData(LiveDetectionsProvider.this.hashCode(), true); completionService.submit(Executors.callable(new ReadDetection(file, false))); while (completionService.take() == null) { Thread.sleep(2); } loaded.add(file.getName()); count++; Logger.getLogger(LiveDetectionsProvider.class.getName()).log(Level.SEVERE, "Detection Message Count:" + count); } detectionsModel.fireStateChanged(DetectionsModel.CHANGE_EVENT_DETECTIONS); timeModel.setLoadingData(LiveDetectionsProvider.this.hashCode(), false); } return null; } } } 

O arquivo é processado na linha com

 completionService.submit(Executors.callable(new ReadDetection(file, false))); 

O arquivo neste momento ainda não terminou de ser escrito e, portanto, falha. Eu tentei dormir meu thread para abrandar, e eu tentei verificar o tamanho do arquivo não mudou. Meu caso de teste para isso é que eu estou descompactando um arquivo tar que contém toneladas de arquivos de 1.000 KB.

Geralmente eu resolvo esse problema criando um arquivo temporário enquanto o arquivo está sendo gravado. Uma vez terminado, renomeio o arquivo e somente o arquivo renomeado pode ser processado.

Use um “arquivo de sinalização”: uma vez que o arquivo.txt esteja “acabado”, indique isso criando um processo file.flg – consumer deve esperar que o .flg apareça.

Primeiro sim compila olha a solução que postei em relação ao código Na minha pergunta. Você substitui

 For(File file: dir){ while(!file.renameTo(file)){ Thread.sleep(1) } // In my code I check to see if the file name is already in the list which // contains files that have been previously loaded if its not I add it to a list // of files to be processed } 

em para

  for (File file : dir) { if (!loaded.contains(file.getName())) { long filesize = 0; boolean cont = true; while (cont) { if (file.length() == filesize) { cont = false; Thread.sleep(3); filesToLoad.add(file); } else { filesize = file.length(); Thread.sleep(3); } } Thread.sleep(3); } } 

desculpe eu esqueci de colocar tags de comentários // na linha que disse fazer o que você precisa fazer aqui.

O que ele faz é verificar cada arquivo no diretório e verificar se você pode renomeá-lo se a renomeação falhar e continuar verificando até que seja capaz de renomear. Nesse ponto, você pode fazer o que precisa com o arquivo. que no meu caso foi tudo depois do loop for que foi substituído. Estou curioso porque meu awnser foi visto como sub-deletado e bloqueado. Essa solução funciona e resolveu meu problema, e qualquer outra pessoa que estivesse com o mesmo problema tentando processar um arquivo que ainda está sendo gravado ou copiado em um diretório que está sendo monitorado por alterações.