简体   繁体   English

文件通过流保存,但无法打开

[英]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. 我正在尝试将图像保存在D:目录中,并且要实现此目的,我将来自FileUpload组件的一些信息保存在Session

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 .. 在名为btnConfirm_Click方法中,创建Session并在btnSave_Click方法中,恢复此信息并尝试保存文件,但是当我检入D:目录时,该文件存在,但是当我打开该文件时,看到了以下消息: 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 C#代码

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
                    {
                    }
              }
         }
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. 您正在使用一个字符串(编码为UTF8)并将其转换为二进制JPG图像。 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. 当您将byte[]转换为string (反之亦然),则会丢失信息,因为文本编码无法(通常)表示所有字节序列。

As @PanagiotisKanovas mentions, you want to be getting the Session['Content'] stream of data. 正如@PanagiotisKanovas提到的那样,您希望获取Session['Content']数据流。

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);
}

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. 它要做的是获取Stream( FileUpload.FileContent )对象的字符串表示形式(通常是类型的名称),将此名称转换为Unicode字符串,然后尝试将其转换回为UFT8字符串的二进制形式,最后存储产生一个文件。

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. Session["Content"]是原始流,因此您可以使用Stream.CopyTo将一个流的内容复制到另一个流。

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

Even better, don't use Session at all. 更好的是,根本不使用Session。 Unless something causes the FileUpload1 control to lose its contents, its content will still be available when you execute your btnSave_Click handler. 除非由于某种原因导致FileUpload1控件丢失其内容,否则当您执行btnSave_Click处理程序时,其内容仍然可用。 In this case you can use FileUpload.Save to save the file directly to disk. 在这种情况下,您可以使用FileUpload.Save将文件直接保存到磁盘。

Besides, using Session is the wrong place to store file data. 此外,使用Session是存储文件数据的错误位置。 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. 会话可以保持很长时间,这意味着即使您不再需要文件数据,它们也将保留在内存中,除非您明确将其删除。

Try to wrap the FileStream in using statement. 尝试在using语句中包装FileStream

FileStream ref: http://msdn.microsoft.com/en-us/library/system.io.filestream.aspx FileStream参考: 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 以下是一般对Streams的引用: http : //msdn.microsoft.com/zh-cn/library/system.io.stream.aspx

Why you have to wrap this statement in a using statement? 为什么必须将此语句包装在using语句中? 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). 当您在代码中使用托管资源(如文件,与数据库的连接或任何其他此类类型)时,要从托管堆(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. 好吧,这不是100%有效的语句,因为当垃圾回收启动并删除所有未使用的对象时,这可能会自动发生。 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. 1)垃圾收集仅在内存压力下启动,而不是计时器启动。
2) Every Managed resource is implemented by Inheriting SafeHandle class. 2)每个托管资源都是通过继承SafeHandle类实现的。 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. http://msdn.microsoft.com/zh-cn/library/system.runtime.interopservices.safehandle.aspx此抽象类具有一个称为Dispose()的方法,该方法仅用于安全释放其创建的所有托管资源。 The dispose method is invoked by the Garbage Collector or when you manually call it. Dispose方法由垃圾收集器或您手动调用时调用。 For example, the using construction is a short cut to the following code: 例如,using结构是以下代码的捷径:

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

PS: Most of the time you should avoid the using statement and also calling Dispose() . PS:大多数时候,您应该避免using语句,还应该调用Dispose() Why? 为什么? Because you have GC, let it do his job. 因为您拥有GC,所以让它完成他的工作。 If you have problems that means you have to look carefully your code in general. 如果遇到问题,则意味着您必须仔细看一下代码。 Let the GC do what it does best. 让GC尽其所能。 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). 最后,仅当您确定没有其他人正在使用您的托管资源(例如在另一个线程中)时,才使用usingDispose() ,意思是它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM