Question

Dans notre application C # WinForms, nous générons des fichiers PDF et le lancement d'Adobe Reader (ou quel que soit le système par défaut gestionnaire .pdf est) par la classe Process. Étant donné que nos fichiers PDF peuvent être importants (environ 200K), nous prenons en charge l'événement Exited pour ensuite nettoyer le fichier temp après.

Le système fonctionne comme requis lorsqu'un fichier est ouvert puis fermé à nouveau. Cependant, lorsqu'un second fichier est ouvert (avant la fermeture Adobe Reader) le deuxième processus quitte immédiatement (puisque Reader utilise maintenant il est des pouvoirs de MDI) et dans notre gestionnaire de Exited notre appel File.Delete devrait échouer, car il est verrouillé par le processus Adobe maintenant rejoint . Cependant, dans Reader nous obtenons la place:

  

Il y avait une erreur d'ouvrir ce document. Ce fichier ne peut être trouvé.

La chose inhabituelle est que si je mets un point d'arrêt de débogage avant la suppression de fichiers et de lui permettre de tenter (et échec) la suppression, puis le système se comporte comme prévu!

Je suis positif que le fichier existe et assez positif que toutes les poignées / fichier flux dans le fichier sont fermés avant de commencer le processus.

Nous lançons avec le code suivant:

// Open the file for viewing/printing (if the default program supports it) 
var pdfProcess = new Process();
pdfProcess.StartInfo.FileName = tempFileName;
if (pdfProcess.StartInfo.Verbs.Contains("open", StringComparer.InvariantCultureIgnoreCase))
{
    var verb = pdfProcess.StartInfo.Verbs.First(v => v.Equals("open", StringComparison.InvariantCultureIgnoreCase));
    pdfProcess.StartInfo.Verb = verb;
}
pdfProcess.StartInfo.Arguments = "/N"; // Specifies a new window will be used! (But not definitely...)
pdfProcess.SynchronizingObject = this;
pdfProcess.EnableRaisingEvents = true;
pdfProcess.Exited += new EventHandler(pdfProcess_Exited);

_pdfProcessDictionary.Add(pdfProcess, tempFileName);

pdfProcess.Start();

Note:. Nous utilisons le _pdfProcessDictionary aux références de magasin pour les objets processus afin qu'ils restent une portée si cet événement Exited peut être soulevé avec succès

Notre nettoyage / événement est sorti:

void pdfProcess_Exited(object sender, EventArgs e)
{
    Debug.Assert(!InvokeRequired);
    var p = sender as Process;
    try
    {
        if (_pdfProcessDictionary.ContainsKey(p))
        {
            var tempFileName = _pdfProcessDictionary[p];
            if (File.Exists(tempFileName)) // How else can I check if I can delete it!!??
            {
                // NOTE: Will fail if the Adobe Reader application instance has been re-used!
                File.Delete(tempFileName);
                _pdfProcessDictionary.Remove(p);
            }

            CleanOtherFiles(); // This function will clean up files for any other previously exited processes in our dictionary
        }
    }
    catch (IOException ex)
    {
        // Just swallow it up, we will deal with trying to delete it at another point
    }
}

Solutions possibles:

  • détectons que le fichier est toujours ouvert dans un autre processus
  • détectons que le second processus n'a pas vraiment été complètement sorti et que le fichier est ouvert dans le premier processus à la place
Était-ce utile?

La solution

juste traité ce il y a quelques jours.

Quand il n'y a pas d'exemple déjà ouvert, le document ouvre dans une nouvelle instance directement.

Quand il y a une instance déjà ouverte, je crois que l'instance fraye une nouvelle instance que vous ne recevez pas en fait une poignée. Ce qui se passe est le contrôle revient à votre fonction immédiatement, ce qui va et puis supprime le fichier avant que la nouvelle instance a eu la chance de lire le fichier -. Par conséquent, il semble ne pas être là

I « résolu » ce en ne supprimant pas les fichiers immédiatement, mais garder la trace des chemins dans une liste, et nuking alors tous lorsque les sorties du programme (Envelopper chaque suppression dans un try / catch avec un bloc catch vide Si le fichier a disparu dans l'intervalle).

Autres conseils

Je suggère l'approche suivante:

  1. Créer des fichiers dans le répertoire temporaire de l'utilisateur ( Path.GetTempPath ). Vous pouvez créer une sous-dossier en dessous.
  2. Essayez de supprimer des fichiers que lorsque la dernière instance de processus se quitte (vous devez compter le nombre de processus que vous avez lancé, à la sortie, décrémenter le compte et quand il devient nul, tentative de suppression (tous) les fichiers qui sont ouvrir jusqu'à présent)
  3. Essayez de nettoyage créé sous-dossier (sous répertoire temporaire) pendant le démarrage et la fin de l'application. Vous pouvez même essayer pour le nettoyage périodique à l'aide minuterie.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top