Como saber se uma cópia de arquivo está ’em andamento’ / completa em java (1.6)

Estou escrevendo um utilitário de monitoramento de diretório em java (1.6) usando sondagem em determinados intervalos usando lastModified long value como a indicação de alteração. Descobri que quando meu intervalo de pesquisa é pequeno (segundos) e o arquivo copiado é grande, o evento de alteração é acionado antes da conclusão real da cópia de arquivo.

Eu gostaria de saber se existe uma maneira de encontrar o status do arquivo como em trânsito, completo etc.

Ambientes: Java 1.6; esperado para trabalhar no windows e linux.

Existem duas abordagens que usei no passado e que são agnósticas em plataformas.

1 / Isto foi para transferências FTP onde eu controlei o que foi colocado, então pode não ser diretamente relevante.

Basicamente, o que quer que seja que esteja colocando um arquivo file.txt , quando terminado, também colocará um arquivo fictício pequeno (provavelmente com zero bytes) chamado file.txt.marker (por exemplo).

Dessa forma, a ferramenta de monitoramento apenas procura o arquivo marcador para aparecer e, quando isso acontece, ele sabe que o arquivo real está completo. Pode então processar o arquivo real e excluir o marcador.

2 / Uma duração inalterada.

Faça com que o seu programa de monitoramento espere até que o arquivo permaneça inalterado por N segundos (em que N é razoavelmente garantido que é grande o suficiente para que o arquivo seja concluído).

Por exemplo, se o tamanho do arquivo não foi alterado em 60 segundos, há uma boa chance de que ele tenha terminado.

Há um ato de equilíbrio entre não pensar que o arquivo foi concluído apenas porque não há atividade nele e a espera, uma vez terminada, antes que você possa começar a processá-lo. Este é um problema menor para cópia local do que FTP.

Esta solução funcionou para mim:

 File ff = new File(fileStr); if(ff.exists()) { for(int timeout = 100; timeout>0; timeout--) { RandomAccessFile ran = null; try { ran = new RandomAccessFile(ff, "rw"); break; // no errors, done waiting } catch (Exception ex) { System.out.println("timeout: " + timeout + ": " + ex.getMessage()); } finally { if(ran != null) try { ran.close(); } catch (IOException ex) { //do nothing } ran = null; } try { Thread.sleep(100); // wait a bit then try again } catch (InterruptedException ex) { //do nothing } } System.out.println("File lockable: " + fileStr + (ff.exists()?" exists":" deleted during process")); } else { System.out.println("File does not exist: " + fileStr); } 

Essa solução depende do fato de você não poder abrir o arquivo para gravação se outro processo o tiver aberto. Ele permanecerá no loop até que o valor de tempo limite seja atingido ou o arquivo possa ser aberto. Os valores de tempo limite precisarão ser ajustados dependendo das necessidades reais do aplicativo. Eu também tentei este método com canais e tryLock (), mas não parece ser necessário.

Você quer dizer que está esperando o lastModified momento para resolver? Na melhor das hipóteses, isso será um pouco imprevisível.

Que tal tentar abrir o arquivo com access de gravação (anexando ao invés de truncar o arquivo, é claro)? Isso não será bem-sucedido se outro processo ainda estiver tentando gravar nele. É um pouco feio, especialmente porque é provável que seja um caso de usar exceções para controle de stream (ick), mas acho que vai funcionar.

Se eu entendi a pergunta corretamente, você está procurando uma maneira de distinguir se a cópia de um arquivo está completa ou ainda em andamento?

Que tal comparar o tamanho do arquivo de origem e de destino (isto é, file.length ())? Se eles forem iguais, a cópia estará completa. Caso contrário, ainda está em andamento.

Não tenho certeza se é eficiente, pois ainda exigiria sondagens. Mas “pode” funcionar.

Você poderia examinar o upload de arquivos on-line com técnicas de barra de progresso – eles usam OutputStreamListener e o gravador personalizado para notificar o ouvinte sobre bytes gravados.

http://www.missiondata.com/blog/java/28/file-upload-progress-with-ajax-and-java-and-prototype/

Upload de arquivo com Java (com barra de progresso)

Costumávamos monitorar a alteração do tamanho do arquivo para determinar se o arquivo está completo ou não.

usamos o ponto final do Arquivo de integração do Spring para fazer a pesquisa de um diretório a cada 200 ms.

Depois que o arquivo for detectado (independentemente de estar completo ou não), temos um filtro de Arquivo do cliente, que terá um método de interface “accept (File file)” para retornar um sinalizador indicando se podemos processar o arquivo.

Se o Falso for retornado pelo filtro, essa ocorrência de FILE será ignorada e será selecionada durante a próxima pesquisa para o mesmo processo de filtragem.

O filtro faz o seguinte:

Primeiro, obtemos o tamanho atual do arquivo. e vamos esperar por 200ms (pode ser menor) e verificar o tamanho novamente. Se o tamanho diferir, tentaremos novamente 5 vezes. Somente quando o tamanho do arquivo parar de crescer, o Arquivo será marcado como COMPLETO (ou seja, retorna verdadeiro).

O código de amostra usado é o seguinte:

 public class InCompleteFileFilter extends AbstractFileListFilter { protected Object monitor = new Object(); @Override protected boolean accept(F file) { synchronized (monitor){ File currentFile = (File)file; if(!currentFile.getName().contains("Conv1")){return false;} long currentSize = currentFile.length(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } int retryCount = 0; while(retryCount++ < 4 && currentFile.length() > currentSize){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } if(retryCount == 5){ return false; }else{ return true; } } } }