web-dev-qa-db-fra.com

Vérifier si le fichier est complètement écrit

Actuellement, je travaille sur le projet qui traite les fichiers du répertoire source dans l'une de ses routines. Il y a un processus Java qui recherche le répertoire spécifié et essaie de lire et de traiter les fichiers s'ils existent. Les fichiers sont quittés volumineux et mis à jour par un autre processus tiers. La question est de savoir comment vérifier si le fichier est complètement écrit? J'essaie d'utiliser file.length() mais il semble que même si le processus d'écriture n'est pas terminé, il renvoie la taille réelle. J'ai le sentiment que la solution devrait dépendre de la plate-forme. Toute aide serait appréciée .

MISE À JOUR: Cette question n'est pas vraiment différente du doublon mais elle a une réponse avec un extrait de code de travail qui est très bien noté.

23
Viktor Stolbin

Le processus de production ferme-t-il le fichier une fois son écriture terminée? Si c'est le cas, essayer d'ouvrir le fichier dans le processus consommateur avec un verrou exclusif échouera si le processus producteur est toujours en cours de production.

10
Will

J'ai réussi à faire fonctionner la solution:

private boolean isCompletelyWritten(File file) {
    RandomAccessFile stream = null;
    try {
        stream = new RandomAccessFile(file, "rw");
        return true;
    } catch (Exception e) {
        log.info("Skipping file " + file.getName() + " for this iteration due it's not completely written");
    } finally {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                log.error("Exception during closing file " + file.getName());
            }
        }
    }
    return false;
}

Merci à @cklab et @Will et à tous ceux qui ont suggéré de regarder de manière "exclusive lock". Je viens de publier du code ici pour inciter d'autres personnes intéressées à l'utiliser. Je crois que la solution de changement de nom suggérée par @tigran fonctionne également mais la solution pure Java est préférable pour moi.

P.S. Initialement, j'ai utilisé FileOutputStream au lieu de RandomAccessFile mais il verrouille le fichier en cours d'écriture.

20
Viktor Stolbin

Une solution simple que j'ai utilisée dans le passé pour ce scénario avec Windows consiste à utiliser boolean File.renameTo(File) et à tenter de déplacer le fichier d'origine vers un dossier de transfert distinct:

boolean success = potentiallyIncompleteFile.renameTo(stagingAreaFile);

Si success est false, alors le potentiallyIncompleteFile est toujours en cours d'écriture.

3
JoshDM

Je ne pense pas qu'il y ait de solution générale à cela. La recherche d'une taille de fichier est incorrecte car certaines applications peuvent définir la taille du fichier avant tout appel en écriture. L'une des possibilités est d'utiliser le verrouillage. Cela nécessitera que le rédacteur accumule un verrou en écriture (ou verrou exclusif). Si vous ne pouvez pas modifier le scripteur, vous pouvez utiliser les outils fournis par le système d'exploitation, comme l'unité de fusion sur Linux pour voir s'il existe un processus qui accède toujours au fichier.

3
kofemann

Si vous prévoyez d'utiliser ce code sur une seule plate-forme, vous pourrez peut-être utiliser installation FileLock de NIO . Mais lisez attentivement la documentation et notez que sur de nombreuses plates-formes, le verrouillage est uniquement consultatif.

Une autre approche consiste à demander à un processus d'écrire le fichier avec un nom que votre processus ne reconnaîtra pas, puis de renommer le fichier en un nom reconnaissable une fois l'écriture terminée. Sur la plupart des plates-formes, l'opération de renommage est atomique si la source et la destination sont le même volume de système de fichiers.

2
JAVAGeek

Si vous pouvez utiliser Java 1.7, jetez un œil aux outils NIO, en particulier Java.nio.channels.FileChannel

ici est un exemple de verrouillage et de lecture du fichier.

1
sevensevens