从读取Excel文件引申出的问题(下)
从上一篇的:从读取Excel文件引申出的问题(上)中,对于从Excel文件中抓取的图片读取速度太慢的,问题主要来源于IComObject对象在经过了Copy和Paste后,造成了对内存及各种计算上的消耗后,速度已大大下降鸟。这几天研究来研究去,也没个结果,索性将这个问题再次提起,借众人之力。
在这一次的实验中,我借助了Marshal类的功能,提取IcomObject对象的指针,通过指针,希望读取Excel文件中图形对象的内容,代码如下:
List<byte> bs =new List<byte>();
IntPtr intptr = item.GetType().TypeHandle.Value;
byte b =1;
int s =0;
while (b >0) {b = Marshal.ReadByte(intptr, s * Marshal.SizeOf(typeof(IntPtr))); s++;bs.Add(b);}
bytes = bs.ToArray();
然后 将读取到的对象内容通过流的形式写入文件。
{
fs.Write(bytes, 0, bytes.Length);
fs.Flush();
fs.Close();
}
最后发现太失败了,内容是读取出来了,但是基本上只读取了10K的内容,图像是无法显示的。这是什么问题呢?
本来嘛,希望通过Marshal来获取对象大小的,最后发现无效,抛出了ArgumentException异常:
类型“Microsoft.Office.Interop.Excel.Shape”不能作为非托管结构进行封送处理;无法计算有意义的大小或偏移量。
算了,还是走回老路吧,最后被逼得没办法了,来招狠的,在图像保存格式上下功夫,这次我不再把获取到的Shape强制转换为BitMap对象,因为从DataObject对象中,我们可以获取到剪贴板对象中支持转换的对象格式,如下:
这下好了,我直接从DataObject对象中获取图片对象,即Image对象,再直接保存,保存的时候会发生一点小问题,即图像格式的问题。
Image img = data.GetImage();
img.Save(@"D:\temp\aa\"+ row +".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
Clipboard.Clear(); // 清除剪贴板内容
Clipboard.Clear(); // 清除剪贴板内容
通过对比,发现保存为GIF格式可获取最高压缩级,Bmp为高保真级存储,消耗的内存和时间还真不是一般的多,当然,我选择了中庸方案:Jpeg格式。下面的数据为同一幅18KB的图片在各种格式下的存储大小,即所谓的压缩比了。
Bmp:145KB
PNG:18KB
GIF:7KB
Tiff:29KB
到最后的完整代码实际上为六行代码。
DataObject data = (DataObject)Clipboard.GetDataObject();
Image img = data.GetImage();
img.Save(@"D:\temp\aa\"+ row +".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
Clipboard.Clear();
img.Dispose();
但是还是那句话,效率上还是上不去,唯一可做的是,通过把图片进行有损压缩,达到一定程度的提高速度,但是这不是最终想的结果,因为Image对象在写入文件时,默认单次写入大小最大为:1KB。不知道还有什么可以提高地方。