klvoek

klvoek

官方文档并不是拿来唬人的

    有些时候官方文档并不是拿来唬人的。曾几何时,微软的MSDN是一个收费的产品。于是习惯免费午餐的我就自然而然的对这种官方文档尤其还是收费的东西产生了抵触感。又加上强大的搜索引擎:譬如谷歌(英文版)、必应,使得在官方文档上能看到的资料在浩瀚的网络资源中也会有很多对应的资源。尽管,使用这些免费资料需要绕很大的弯子。可是,我喜欢免费的感觉,穷嘛。

    后来弯路绕多了,又发现微软的MSDN网站上的文档竟然也很有价值。于是在谷歌资料的时候对MSDN的官方文档解释多了一点嗜好(这个是免费的)。然而,参考MSDN的官方文档确是作为马后炮的——为的是在问题解决后能够得到一个官方、权威的佐证(穷毛病都在了)。不曾想,却有了下面深入的一课。

    数天前写了一段代码,主要是为了完成文件字节流操作。在一个文件中写入多个图像数据。然后文件格式简单的定位 [[imgDataLengthInByte][imgData]] 。主要代码写入图片数据的代码为

    curPos = writeStream.Position;
    writeStream.Write(BitConverter.GetBytes((long)0), 0, 8);
    curLen = writeStream.Length;
    image.Save(writeStream, image.RawFormat);          
    writeStream.Seek(curPos, SeekOrigin.Begin);
    writeStream.Write(BitConverter.GetBytes(writeStream.Length - curLen), 0, 8);
    writeStream.Seek(0, SeekOrigin.End);

    然后读取回来,这一切很正常。因为在我的win7上运行很正常。

    datas = new byte[8];
    readStream.Read(datas, 0, 8);
    imgDataLength = BitConverter.ToInt64(datas, 0);     long readed = 0;
    int dataReaded = 0;
    using (MemoryStream ms = new MemoryStream())
    {
        datas = new byte[1024];
        while (readed < imgDataLength)
        {
            dataReaded = readStream.Read(datas, 0, 1024);
            ms.Write(datas, 0, dataReaded);
            readed += dataReaded;
        }
        image = Image.FromStream(ms);
    }
    这两段代码工作的很好,写入图片,读取图片。然而悲催的事情终于要发生了。在昨天我想做点。。的事情的时候,一个异常摧毁了晚上睡觉的欲望,熬夜到了三点。开始的时候,是因为明明上面好好的代码逻辑,同样的代码拷贝到其他项目中竟然报出了错误。这个错误是发生在读取写入数据的文件时因为未能正确获得保存的图片字节长度的值而发生的,获取的图片字节长度为一个比实际值非常大的值。单步调试发现,long型转换的字节数组在读取的时候本不该有值的后几个字节却有了值。

        而代码逻辑必然使 [imgDataLengthInByte][imgData] 的顺序存在

                        imgDataLengthInByte imgData

        然而,实际情况是可能发生了图片数据覆盖了我写入的图片长度数据

                        imgDataLengthInByte imgData

    根据猜测再次进行单步调试,修改代码。在写入的时候,先将image的数据写入一个MemoryStream中,获取MemoryStream的长度作为Image字节数据的大小,然后在将Image的数据写入到目标流中。比较目标流的大小。结果发现,目标流的大小竟然和Image字节数据大小相同。这说明写入的长度值被图片数据覆盖了。赶紧去Google Bitmap.Save MSDN,MSDN上标注着,调用Save(Stream,ImageFormat ) 方法向目标流中写入图片数据时,该操作会从目标流的0位移处开始写入数据,如果在之前已经在该流中写入了数据,那么流数据会损坏。(就是你写入的数据没了?)

    于是修改图片数据的写入方式,和图片数据的读取方式类似

 

    curPos = writeStream.Position;
    writeStream.Write(BitConverter.GetBytes((long)0), 0, 8);
    curLen = writeStream.Length;
    MemoryStream ms = new MemoryStream() ;
    image.Save(ms, image.RawFormat);
    ms.Seek(0, SeekOrigin.Begin);
    int readed = 0;
    datas = new byte[1024];
    while (ms.Position < ms.Length)
    {
        readed = ms.Read(datas, 0, 1024);
        writeStream.Write(datas, 0, readed);
    }
    ms.Close();     writeStream.Seek(curPos, SeekOrigin.Begin);
    writeStream.Write(BitConverter.GetBytes(writeStream.Length - curLen), 0, 8);
    writeStream.Seek(0, SeekOrigin.End);

    代码明显变长了。运行后果然没有问题了。于是问题有了解决办法。可是之前我好端端的和现在为什么报错的原因究竟是什么?于是糟糕的三个小时和第二天来了~

 

    一直到凌晨三点,我都在纠结为什么我之前的项目能够正常运行,而且是有保存图片读取图片的操作的?为此,我还特意运行了一下之前的项目程序。没有任何问题。然后在运行我的测试代码,kao,又是异常。正常的时候就是Image.Save会从目标流当前位置写入图片数据,为什麽我的测试代码里会始终从目标流的绝对0偏移位置开始写入图片数据。为什麽,为什麽,很伤人的有木有,有木有~~ 于是乎,后来我就完全的是在,启动调试,选择图片,断点,尼玛,为什么还是从流的起点开始写?停止调试。再启动调试,再选择图片,断点,尼玛...。 于是,后来接近崩溃的我已经开始怀疑是不是真的有人品问题?我是不是该等明天一觉醒来再运行就万事大吉了?这一切肯定不是真的?是不是我只要闭上眼再睁开眼...? 一定是的 ,  尼玛... 还是早点睡,明天起来上班再...。(如果在debug问题的时候陷入这种状态,最好休息一下。又耗心神又不能获得效果。太累~)

    悲剧的一天,开始在win7电脑上。测试代码,调试,咦正常?不是吧,这。问题到底出在哪里呢?于是我想到了几个不同的地方:

        首先,系统(win7 or XP)。于是找了几个仍在用XP的同学,程序扔过去,我擦。结果没问题呐

    问题一定出在哪里,这一定不是真的,一定不是真的...。诶,敏锐的我注意到了另外一个不同的地方:

        第二,图片格式?我现在使用的是jpg,我电脑上使用的是png。对的,于是叮咣叮咣地爬上楼。下载测试带吗,调试...额,

    问题一定出在另外的地方,对的,对的。一定是的。难道是因为我图片大小的问题?我那个XP上的图片是128×128的,而现在这个是不规则的而且还有美女哟。额,不应该的,那岂不是说我的那个头像太丑了?...就这样一个纠结的上午过去了。

    不行,这样下去岂不是一天都不用干正事儿了,还是先放一放吧..

    

    吃过晚饭,重新打开测试代码。额,png有问题,jpg正常?额,重新整理代码,突出问题。果不其然,再找小花(sxwgf)win7实验。额?win7和XP有差别?

序号 在XP下测试效果 在Win7下测试效果
jpg jpg jpg
gif gif gif
png png png
bmp bmp bmp

 

     能力有限,不能确定Save方法对于不同系统win7或XP、不同图片格式(jpg,gif)和(png,bmp)的处理有什么不同。目前暂时总结就是,MSDN上标注的会令目标流(Stream对象)中的数据出错,此言非虚啊。而在win7上Save方法对四种图片格式都表示出了我所期望的结果,从指定流的当前位置将数据写入。而在xp上时对png和bmp则是从目标流的开始位置写入数据。以后要尽量能够去读官方文档,对官方文档中提到的不确定因素要尽量去验证、确认。避免在程序中留下隐患。

    蛋疼的一天过去了,继续写我刚刚有提到的...。

 

    测试代码围观:http://www.itivy.com/DownloadFile.ashx?id=634463678389955139

    本文剧终,谢谢观看。

 

 

我也来参与讨论

  1. 回复 2011-8-5 17:56:43 by NinoFocus

    当我把鼠标移到图像上,弹出一个更大的图像时,我就狂点右上角的X 想将其关掉
  2. 回复 2011-8-8 8:39:41 by klvoek

    @NinoFocus:你是永远找不到那个图标的,哈哈
你还可以输入600/600个字符 发表评论
称呼: (必填) 登录 | 开通博客
邮箱: (选填) 你的邮箱地址不会被公开
网站: (选填)
验证码: (必填)
看不清换一张 看不清楚换一张