Lucas_Santos
Lucas_Santos

Reputation: 4740

File is saved through Stream but can't be opened

I'm trying save a image in my D: directory, and to accomplish this, I'm save in Session some informations from my FileUpload component.

In my method called btnConfirm_Click I create my Session and in my btnSave_Click method I recover this information and try to save the file, but when I check in my D: directory, the file exist but when I open this file, I saw the message: The windows photo viewer can not open this picture because the file appears to be damaged, corrupted, or is too big ..

Someone can help me ?

C# Code

protected void btnConfirm_Click(object sender, EventArgs e)
{
 if (FileUpload1.HasFile)
            {
                string sFileName = FileUpload1.FileName;
                string fileExtension = System.IO.Path.GetExtension(sFileName).ToLower();
                foreach (string ext in new string[] { ".jpeg", ".jpg", ".png" })
                {
                    if (fileExtension == ext)
                    {
                        Session["Document"] = sFileName + fileExtension;
                        Session["Byte"] = FileUpload1.FileBytes;
                        Session["Content"] = FileUpload1.FileContent;
                        byte[] b = (byte[])Session["Byte"];
                    }
                }
           }
}


protected void btnSave_Click(object sender, EventArgs e)
        {
                if (Session["Document"].ToString() != null)
                {
                    try
                    {
                        byte[] byteArray = Encoding.UTF8.GetBytes(Session["Content"].ToString());                        
                        MemoryStream stream = new MemoryStream(byteArray);

                        sPath = "D:/123.jpg";
                        FileStream fileStream = File.Create(sPath, (int)stream.Length);                        
                        byte[] bytesInStream = new byte[stream.Length];
                        stream.Read(bytesInStream, 0, bytesInStream.Length);                        
                        fileStream.Write(bytesInStream, 0, bytesInStream.Length);
                    }
                    catch
                    {
                    }
              }
         }

Upvotes: 0

Views: 3367

Answers (3)

mynkow
mynkow

Reputation: 4548

Try to wrap the FileStream in using statement.

FileStream ref: http://msdn.microsoft.com/en-us/library/system.io.filestream.aspx

Here is the reference to Streams in general: http://msdn.microsoft.com/en-us/library/system.io.stream.aspx

Why you have to wrap this statement in a using statement? When you use managed resources in your code like files, connections to database or any other of this kind you have to specify manually when you want these resource to be freed from the managed heap (your RAM). Well, this is not 100% valid statement because this can happen automatically when the garbage collection kicks in and removes the all unused objects. There are some points you must know to understand what kind of code you should write.

1) The garbage collection kicks in only on memory pressure, not timer.
2) Every Managed resource is implemented by Inheriting SafeHandle class. http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx This abstract class has a method called Dispose() which only job is to safely free any managed resources it created. The dispose method is invoked by the Garbage Collector or when you manually call it. For example, the using construction is a short cut to the following code:

var file;
try{ // code }
finally { file.Dispose(); }

PS: Most of the time you should avoid the using statement and also calling Dispose(). Why? Because you have GC, let it do his job. If you have problems that means you have to look carefully your code in general. Let the GC do what it does best. Finally, use using or Dispose() only, I mean it, only when you are sure no one else is using your managed resource (for example in another thread).

Upvotes: 0

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131180

The message says that the file doens't contain image data. Your code never stores the file's content to disk.

What it does is to get the string representation of a Stream (FileUpload.FileContent) object (typically the name of the type) converts this name to a Unicode string, then tries to convert it back to binary as a UFT8 string and finally stores the results in a file.

The contents of Session["Content"] is the original stream, so you can just copy the contents of one stream to the other using Stream.CopyTo, eg.

var sourceStream=(Stream)Session["Content"];
using(var fileStream=File.Create(targetPath,sourceStream.Length);
{
    sourceStream.CopyTo(fileStream);
}

Even better, don't use Session at all. Unless something causes the FileUpload1 control to lose its contents, its content will still be available when you execute your btnSave_Click handler. In this case you can use FileUpload.Save to save the file directly to disk.

Besides, using Session is the wrong place to store file data. Session uses either the machine's memory or a database to store its data, which can result in poor performance when you store large data there. Sessions stay alive for a long time which means that the file data will remain in memory even after you no longer need it, unless you explicitly remove it.

Upvotes: 1

Jeff Foster
Jeff Foster

Reputation: 44696

byte[] byteArray = Encoding.UTF8.GetBytes(Session["Content"].ToString());

This line looks very wrong. You are taking a string (encoded as UTF8) and trying to turn it into a binary JPG image. This won't work. You need to keep the original image in binary (not textual + encoding) form. When you turn byte[] into a string (or vice-versa) there is an information loss because a textual encoding can't (in general) represent all byte sequence.

As @PanagiotisKanovas mentions, you want to be getting the Session['Content'] stream of data.

As an aside, you aren't closing your streams, so it's possible that when you try to open the file the object is still locked.

using (FileStream fileStream = File.Create(sPath, (int)stream.Length)) {
   byte[] bytesInStream = new byte[stream.Length];
   stream.Read(bytesInStream, 0, bytesInStream.Length);                        
   fileStream.Write(bytesInStream, 0, bytesInStream.Length);
}

Upvotes: 5

Related Questions