32 votes

Java : Surveiller un répertoire pour déplacer des fichiers volumineux

J'ai écrit un programme qui surveille un répertoire et lorsque des fichiers y sont créés, il en change le nom et les déplace dans un nouveau répertoire. Dans ma première implémentation, j'ai utilisé l'API Watch Service de Java, ce qui a bien fonctionné lorsque je testais des fichiers de 1 kb. Le problème qui s'est présenté est qu'en réalité, les fichiers créés sont de 50 à 300 Mo. Dans ce cas, l'API de surveillance trouvait immédiatement le fichier mais ne pouvait pas le déplacer car il était toujours en cours d'écriture. J'ai essayé de placer l'observateur dans une boucle (qui générait des exceptions jusqu'à ce que le fichier puisse être déplacé) mais cela semblait plutôt inefficace.

Comme cela n'a pas fonctionné, j'ai essayé d'utiliser un timer qui vérifie le dossier toutes les 10s et déplace les fichiers quand il le peut. C'est la méthode que j'ai fini par adopter.

Question : Existe-t-il un moyen de signaler la fin de l'écriture d'un fichier sans vérifier les exceptions ou comparer continuellement la taille ? J'aime l'idée d'utiliser l'API Watcher une seule fois pour chaque fichier au lieu de vérifier continuellement avec un timer (et de rencontrer des exceptions).

Toutes les réponses sont très appréciées !

nt

0voto

enigma969 Points 184

Si vous n'avez pas le contrôle sur le processus d'écriture, enregistrez toutes les ENTRY_CREATED et observer s'il y a motifs .

Dans mon cas, les fichiers sont créés via WebDav (Apache) et beaucoup de fichiers temporaires sont créés mais aussi deux ENTRY_CREATED sont déclenchés pour le même fichier. Le deuxième ENTRY_CREATED indique que le processus de copie est terminé.

Voici mon exemple ENTRY_CREATED événements. Le chemin d'accès absolu au fichier est imprimé (votre journal peut être différent, en fonction de l'application qui écrit le fichier) :

[info] application - /var/www/webdav/.davfs.tmp39dee1 was created
[info] application - /var/www/webdav/document.docx was created
[info] application - /var/www/webdav/.davfs.tmp054fe9 was created
[info] application - /var/www/webdav/document.docx was created
[info] application - /var/www/webdav/.DAV/__db.document.docx was created 

Comme vous le voyez, j'ai deux ENTRY_CREATED des événements pour document.docx . Après le deuxième événement, je sais que le fichier est complet. Les fichiers temporaires sont évidemment ignorés dans mon cas.

0voto

Varun Chaudhary Points 53

J'ai eu le même problème et la solution suivante a fonctionné pour moi. Tentative précédente infructueuse - J'ai essayé de surveiller l'état "lastModifiedTime" de chaque fichier, mais j'ai remarqué que la croissance de la taille d'un gros fichier peut faire une pause pendant un certain temps (la taille ne change pas continuellement).

Idée de base - Pour chaque événement, créez un fichier de déclenchement (dans un répertoire temporaire) dont le nom est au format suivant : - 1.

Nom du fichier original_dernier temps modifié_nombre d'essais

Ce fichier est vide et tout le jeu est seulement dans le nom. Le fichier original ne sera pris en compte qu'après avoir passé des intervalles d'une durée spécifique sans changement dans son statut "last Modified time". (Note - comme il s'agit d'une statistique de fichier, il n'y a pas de surcharge -> O(1)).

NOTE - Ce fichier de déclenchement est géré par un service différent (disons " "). Déclencheur de fichiers ').

Avantage -

  1. Pas de sommeil ou d'attente pour retenir le système.
  2. Soulage l'observateur de fichiers pour surveiller d'autres événements.

CODE pour FileWatcher -

val triggerFileName: String = triggerFileTempDir + orifinalFileName + "_" + Files.getLastModifiedTime(Paths.get(event.getFile.getName.getPath)).toMillis + "_0"

// creates trigger file in temporary directory
val triggerFile: File = new File(triggerFileName)
val isCreated: Boolean = triggerFile.createNewFile()

if (isCreated)
    println("Trigger created: " + triggerFileName)
else
    println("Error in creating trigger file: " + triggerFileName)

CODE pour FileTrigger (tâche cron d'un intervalle de 5 minutes) -

 val actualPath : String = "Original file directory here"
 val tempPath : String = "Trigger file directory here"
 val folder : File = new File(tempPath)    
 val listOfFiles = folder.listFiles()

for (i <- listOfFiles)
{

    // ActualFileName_LastModifiedTime_NumberOfTries
    val triggerFileName: String = i.getName
    val triggerFilePath: String = i.toString

    // extracting file info from trigger file name
    val fileInfo: Array[String] = triggerFileName.split("_", 3)
    // 0 -> Original file name, 1 -> last modified time, 2 -> number of tries

    val actualFileName: String = fileInfo(0)
    val actualFilePath: String = actualPath + actualFileName
    val modifiedTime: Long = fileInfo(1).toLong
    val numberOfTries: Int = fileStats(2).toInt

    val currentModifiedTime: Long = Files.getLastModifiedTime(Paths.get(actualFilePath)).toMillis
    val differenceInModifiedTimes: Long = currentModifiedTime - modifiedTime
    // checks if file has been copied completely(4 intervals of 5 mins each with no modification)
    if (differenceInModifiedTimes == 0 && numberOfTries == 3)
    {
        FileUtils.deleteQuietly(new File(triggerFilePath))
        println("Trigger file deleted. Original file completed : " + actualFilePath)
    }
    else
    {
        var newTriggerFileName: String = null
        if (differenceInModifiedTimes == 0)
        {
            // updates numberOfTries by 1
            newTriggerFileName = actualFileName + "_" + modifiedTime + "_" + (numberOfTries + 1)
        }
        else
        {
            // updates modified timestamp and resets numberOfTries to 0
            newTriggerFileName = actualFileName + "_" + currentModifiedTime + "_" + 0
        }

        // renames trigger file
        new File(triggerFilePath).renameTo(new File(tempPath + newTriggerFileName))
        println("Trigger file renamed: " + triggerFileName + " -> " + newTriggerFileName)
    }    
}

-1voto

emory Points 6319

Je suppose que java.io.File.canWrite() vous dira quand un fichier a fini d'écrire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X