从数据库读取图片发生“无效的参数”异常

介绍

我发现对于很多人来说,当从数据库里载入一张图片然后重新创建成一张图片显示的话会有这样一个问题—-当他们尝试重新创建新的图片的时候,会抛出一个“无效的参数”异常

因此,本文介绍该异常如何产生。并且我希望未来当我或是你发生这个错误的时候还能有所帮助。。

背景

存储图片到数据库里面是一个很有效的想法。很多人在一些场合都会这样做。的确,这是一个很好的想法。在图片很小的情况下,或者图片不是太多。在这两种情况下,当你需要图片的时候,你会实时去加载它们。而当你不需要的时候如果从数据库里加载图片会浪费很多带宽。并使得你的程序有一些慢。

但问题是这种方法也很容易发生错误。–尤其是你使用字符串连接,然后组合到你的SQL语句里面—并且这个错误只有当你打算使用存储的信息的时候才会发生。然后,看起来似乎是你的读取代码写错了—不可能—它是正常的。我在其他地方都可以的。。

从数据库里加载图片

重数据库里读取一张图片然后转换成图片显示是很简单的。

using (SqlConnection con = DBAccess.DBCon)
                        {
                        using (SqlCommand cmd = new SqlCommand(“SELECT picture FROM Pictures WHERE Id=@ID”, con))
                            {
                            cmd.Parameters.AddWithValue(“@ID”, Id);
                            SqlDataReader reader = cmd.ExecuteReader();
                            if (reader.Read())
                                {
                                byte[] data = (byte[])reader[“Picture”];
                                using (MemoryStream stream = new MemoryStream(bytes))
                                    {
                                    myImage = new Bitmap(stream);
                                    }
                                }
                            }
                        }
但是-如果data因为一些原因不是有效的图片,那么这一行
myImage = new Bitmap(stream);
将会抛出一个异常—无效的参数

只有当你真正看了从数据库里返回到data里的数据-而不是简单的瞄了一眼调试器,你才能注意到是什么原因。。

{byte[21]}
[0] 83
[1] 121
[2] 115
[3] 116
[4] 101
[5] 109
[6] 46
[7] 68
[8] 114
[9] 97
[10] 119
[11] 105
[12] 110
[13] 103
[14] 46
…
它看起来不像是错的,所以它可能就是你想要的。-虽然21字节是一个很大的线索:你的图片可能只有21字节长?那图片可真小。。

但是,上面的是可以读懂的。。稍微练习一下。。每个字节是一个ASCII码。。

“83” is an uppercase ’S’
“121” is an lowercase ‘y’
“115” is an lowercase ’s’
“116” is an lowercase ’t’
“101” is an lowercase ‘e’
“109” is an lowercase ’m’
“46” is a ‘.’
“68” is an uppercase ’D’
“114” is an lowercase ‘r’
“97” is an lowercase ‘a’
“119” is an lowercase ‘w’
“105” is an lowercase ‘i’
“110” is an lowercase ‘n’
“103” is an lowercase ‘g’
“46” is an lowercase ‘.’
…
简而言之,你从数据库里得到的数据是一个人类可以读懂的字符串,意思是是
“System.Drawing.Bitmap”
当这个Image类试图把它转换成一个图片的时候,必然是不可能的。抛出异常就是必然的了。。代码是正确的。data才是问题所在。

保存图片到数据库

这才是引发问题的地方。 通常。这是因为把字符串连接起来构造SQL语句引起的。

string sql = “INSERT INTO myTable (imageData) VALUES (‘” + myImage + “’)”;
不要在SQL语句中包含image对象—它会调用Image的ToString方法。而这个方法会返回
“System.Drawing.Bitmap”
因此你的上一条语句其实就相当于
INSERT INTO myTable (imageData) VALUES (‘System.Drawing.Bitmap’)
存储并不会有什么问题—但是事实上只是把Image的类型名保存了。而你傻傻的以为是图片数据本身。

这还不是唯一的一个不让你直接连接字符串构造SQL语句的原因,如果你想知道其他原因。 使用Google 搜索Bobby Tables,—这不是闹着玩的。。

好了。其实把代码写正确也不难,虽然可能得多花一些时间。但是,它可以帮助提高代码的可读性和可靠性。而你要做的就是使用一个参数化的查询。

首先,把图片转换到一个字节数组里。

Image myImage = Image.FromFile(@“D:\Temp\MyPic.jpg”);
            byte[] data;
            using (MemoryStream ms = new MemoryStream())
                {
                myImage.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                data = ms.ToArray();
                }
然后在SqlCommand对象里使用这些字节
using (SqlConnection con = new SqlConnection(strConnect))
                {
                con.Open();
                using (SqlCommand com = new SqlCommand(“INSERT INTO Pictures (Picture) VALUES (@IM)”, con))
                    {
                    com.Parameters.AddWithValue(“@IM”, data);
                    com.ExecuteNonQuery();
                    }
                }

结束之前

不。。你不能取回那些你已经错误的存在数据库的信息。。所以。。全部删掉把。然后重新存一遍。

许可

本文包括代码和源文件,在CPOL下授权

 

原文地址:Why-do-I-get-a-Parameter-is-not-valid-exception-wh 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

comments powered by Disqus