2009-07-30 11 views
0

J'essaye de créer un utilitaire en C# en utilisant le framework MVC où un utilisateur télécharge une image qui est utilisée pour rogner des pièces à utiliser comme icônes de miniatures (une seule l'utilisateur à la fois le fera à tout moment). L'utilisateur peut alors télécharger une image différente et continuer à recadrer.Impossible d'écraser les images téléchargées en C# en utilisant l'objet Image

J'ai une action de contrôleur qui manipule le téléchargement de dossier prenant l'image, le convertissant de n'importe quel format en jpeg et l'enregistrant comme "temp.jpg" (je sais que ce n'est pas un contrôleur mince, mais c'est juste à des fins de test). Quand ils téléchargent l'image suivante je veux remplacer ce temp.jpg avec cette nouvelle image. Ce contrôleur fonctionne très bien en développement sur ma machine, mais en production après que l'utilisateur télécharge la première image et tente de le remplacer par une autre image, il obtient l'erreur suivante:

"le processus ne peut pas accéder au fichier car il est utilisé par un autre processus "

Il me semble que le fichier" temp.jpg "est verrouillé après le premier téléchargement et je n'arrive pas à comprendre comment éviter cela.

Toutes les suggestions ou idées alternatives sont les bienvenues.

Décomposer de ce que mon code ne:

  • Vérifie si l'image à télécharger existe sur le serveur et supprime si trouvé
  • Enregistre l'image comme il est avec son nom de fichier d'origine et l'extension
  • Vérifie le fichier « temp.jpg » et supprime si trouvé
  • ouvre l'image originale dans un objet System.Drawing.Image pour convertir en jpeg
  • Enregistrez-le en tant que nouveau "temp.jpg" pour remplacer le fichier supprimé.

Mon code:

 [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult PicUpload(DateTime sd, FormCollection collection) 
    { 
      foreach (string file in Request.Files) 
      { 
       HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase; 
        if (hpf.ContentLength == 0) 
         continue; 
        string savedFileName = Path.Combine(
         AppDomain.CurrentDomain.BaseDirectory + "Content\\AdContent\\", 
         Path.GetFileName(hpf.FileName)); 

        FileInfo temp = new FileInfo(savedFileName); 
        if (temp.Exists) temp.Delete(); 

        hpf.SaveAs(savedFileName); 

        string tempFileName = AppDomain.CurrentDomain.BaseDirectory + "Content\\AdContent\\temp.jpg"; 

        temp = new FileInfo(tempFileName); 
        if (temp.Exists) temp.Delete(); 

        EncoderParameters codecParams = new EncoderParameters(1); 
        codecParams.Param[0] = new EncoderParameter(Encoder.Quality, 100L); 
        ImageCodecInfo[] encoders; 
        encoders = ImageCodecInfo.GetImageEncoders(); 

        Image newPic = Image.FromFile(savedFileName); 
        newPic.Save(tempFileName, encoders[1], codecParams); 
        newPic.Dispose(); 

        FileInfo tmp = new FileInfo(savedFileName); 
        if (tmp.Exists) tmp.Delete(); 
        return RedirectToAction("Create", new { startdate = String.Format("{0:MM-dd-yyyy}", sd) }); 
      } 
      return RedirectToAction("Create", new { startdate = String.Format("{0:MM-dd-yyyy}", sd) }); 
    } 

Répondre

2

Il s'avère que je ne libérais pas correctement les ressources de l'image dans une autre section de mon code qui renvoyait les propriétés de largeur et de hauteur de l'image. Aussi au lieu d'utiliser la méthode Dispose();, je mets le code dans un « bloc à l'aide » au lieu comme ceci:

  using (Image newPic = Image.FromFile(savedFileName)) 
      { 
       newPic.Save(tempFileName, encoders[1], codecParams); 
      } 

Cela a fonctionné comme un charme et je peux maintenant supprimer le fichier temp.jpg en toute impunité.

0

Vous pouvez utiliser un fichier temporaire au nom unique pour tempFileName au lieu de "temp.jpg." System.IO.Path a une méthode GetTempFileName() que vous pouvez utiliser pour cela.

Une autre option serait d'utiliser la méthode GetRandomFileName() (également System.IO.Path) qui retourne un chemin aléatoire ou nom de fichier, il est juste une question de faire un petit changement à votre code:

- string tempFileName = AppDomain.CurrentDomain.BaseDirectory + "Content\\AdContent\\temp.jpg"; 
+ string tempFileName = AppDomain.CurrentDomain.BaseDirectory + "Content\\AdContent\\" + System.IO.Path.GetRandomFileName(); 
+0

Cela peut fonctionner, même si je dois enregistrer le nom de fichier et mon avis font référence. – hotbot86

+0

C'est probablement ce que vous aurez à faire. –

+0

Une question cependant, si le fichier est verrouillé, même si j'obtiens un nom de fichier aléatoire, ce fichier ne serait-il pas verrouillé quand j'essayerais de le nettoyer plus tard après que l'utilisateur ait téléchargé un nouveau fichier avec un nouveau nom aléatoire ? – hotbot86

1

System.Drawing .Image.Save() ne peut pas enregistrer au même emplacement que le fichier a été ouvert:

De the docs: "Enregistrer l'image dans le même fichier à partir duquel elle a été construite n'est pas autorisée et déclenche une exception."

+0

Je ne l'enregistre pas au même endroit. J'ai édité ma question pour faire ce que mon code essaye de faire plus clair. En bref je sauvegarde le fichier, puis j'essaie de créer une copie nommée "temp.jpg" mais si ce fichier est déjà bloqué du téléchargement précédent, je ne peux pas le supprimer pour le remplacer. – hotbot86

1

Utilisez un « panneau » commande, et l'enregistrer comme BMP, PNG, quelle que soit

Questions connexes