Using a MemoryStream to Load .jpg without blocking the file by process?

6.6k Views Asked by At

Im having a sort of an editor, that has some strings and a picture displayed in the ui and iam saving the data in a textfile and a detached .jpg file with the same name.

Now when iam trying to override the .jpg file by File.Replace, it says that the picture is blocked by another process which is obviously the process of my own application.

I hope that the memorystream can fix this because it is handled in the RAM. So i would like to load all the jpg files by a memorystream but i dont understand how to load anything with the memorystream, if that is a possible solution to my problem at all..

Edit: Basicly the code snippit this is about is this one :

private void CopyPicture(bool PictureHasChanged)
    {
        try
        {   //kopiere die datei nur, wenn sie nicht bereits vorhanden ist.  
            if (File.Exists(TargetFolder + Exercise.Name + ".jpg") == false)
            {//kopiert das neue bild in das zielverzeichnis
                File.Copy(Exercise.Bild.UriSource.LocalPath, TargetFolder + Exercise.Name + ".jpg");
            }
            else
            {
                //wenn das Bild einer bestehenden übung geändert wurde
                if (PictureHasChanged)
                {
                    //überprüft ob eine datei mit dem namen existiert 
                    if (File.Exists(TargetFolder + Exercise.Name + ".jpg") == true)
                    {//löscht die existente datei
                        File.Replace(Exercise.Bild.UriSource.LocalPath, TargetFolder + Exercise.Name + ".jpg", TargetFolder + Exercise.Name + ".jpg");
                    }

                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message + "\n\n" + ex.Source);
            return;
        }

    }

and i have the picture stored internal in a simple list as a bitmapimage by : new BitmapImage(new Uri(f.FullName.ToString().Remove(f.FullName.Length - 4, 4) + ".jpg",UriKind.RelativeOrAbsolute))

i hope that this helps to understand the problem better

EDIT 2: now iam doing the following in order to load the Picture:

FileStream fsSource = new FileStream(JpgTarget, FileMode.Open, FileAccess.Read);
                        byte[] bytes = new byte[fsSource.Length];
                        using (fsSource)
                        {
                            // Read the source file into a byte array.
                            int numBytesToRead = (int)fsSource.Length;
                            int numBytesRead = 0;
                            while (numBytesToRead > 0)
                            {
                                // Read may return anything from 0 to numBytesToRead.
                                int n = fsSource.Read(bytes, numBytesRead, numBytesToRead);

                                // Break when the end of the file is reached.
                                if (n == 0)
                                    break;

                                numBytesRead += n;
                                numBytesToRead -= n;
                            }
                            //numBytesToRead = bytes.Length;
                        }

                        BitmapImage Image = new BitmapImage();
                        //erstellt das bitmap für die liste
                        using (MemoryStream Memstream = new MemoryStream(bytes))
                        {

                            Image.BeginInit();
                            Image.StreamSource = Memstream;
                            Image.CacheOption = BitmapCacheOption.OnLoad;
                            Image.EndInit();
                            Image.Freeze();
                        }
                        fsSource.Close();

But it Keeps telling me that The Pictrue, iam trying to overwrite is already in use by another process.

Edit 3: I tried to use pennie Pet's solution and ended up with this, having the same problem with the locked file:

  Bitmap newBitmap = GetImageFromByteArray(File.ReadAllBytes(JpgTarget));

                        using (MemoryStream memory = new MemoryStream())
                        {
                            newBitmap.Save(memory, newBitmap.RawFormat);
                            memory.Position = 0;
                            BitmapImage bitmapImage = new BitmapImage();
                            bitmapImage.BeginInit();
                            bitmapImage.StreamSource = memory;
                            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                            bitmapImage.EndInit();


                            //fügt der liste die aus der textdatei gelesene übung hinzu
                            List.Add(new Uebung(text, Sitting, wdh, bitmapImage, f.Name.Substring(0, f.Name.Length - 4)));
                        }

See the GetImageFromByteArray methode in PenniePet's post.

Last Edit:

It was totally my fault and it really embarrass me, i forgot that i was Loading the Image at another point. Since i fixed it, the locked-problem does not exist anymore.

I picked PenniePete's Awnser as correct, because iam currently using it, as it was the last one i tried, and he also opened my eyes to my fail.

I hope you other guys wont be mad. Thanks for all of your help!

3

There are 3 best solutions below

2
On BEST ANSWER

If I understand right, you want to read the .jpg file, and convert it into a .Net Bitmap object in a way that guarantees that the .jpg file does not end up being locked. If so, here are some code snippets from a previous answer of mine: https://stackoverflow.com/a/16576471/253938

Bitmap newBitmap = GetImageFromByteArray(File.ReadAllBytes(fileName));

and

  /// <summary>
  /// Method that uses the ImageConverter object in .Net Framework to convert a byte array, 
  /// presumably containing a JPEG or PNG file image, into a Bitmap object, which can also be 
  /// used as an Image object.
  /// </summary>
  /// <param name="byteArray">byte array containing JPEG or PNG file image or similar</param>
  /// <returns>Bitmap object if it works, else exception is thrown</returns>
  public static Bitmap GetImageFromByteArray(byte[] byteArray)
  {
     Bitmap bm = (Bitmap)_imageConverter.ConvertFrom(byteArray);

     if (bm != null && (bm.HorizontalResolution != (int)bm.HorizontalResolution ||
                        bm.VerticalResolution != (int)bm.VerticalResolution))
     {
        // Correct a strange glitch that has been observed in the test program when converting 
        //  from a PNG file image created by CopyImageToByteArray() - the dpi value "drifts" 
        //  slightly away from the nominal integer value
        bm.SetResolution((int)(bm.HorizontalResolution + 0.5f), 
                         (int)(bm.VerticalResolution + 0.5f));
     }

     return bm;
  }
4
On

You have to use

bitmap.CacheOption = BitmapCacheOption.OnLoad;

otherwise your image file is locked.

9
On

Be sure that you close the stream after saving the .jpg file.

When reading the file be sure that you set only Read access when open the stream.

System.IO.FileStream f = new System.IO.FileStream(sPath, FileMode.Open,
                                                         FileAccess.Read);

Use f stream to read the bytes and create an instance of MemoryStream using the read bytes:

System.IO.MemoryStream x = new System.IO.MemoryStream(buffer)