从读取Excel文件引申出的问题(上)

事件起因源于偶然在百度知道看到一个提问,说是他的Excel文件中共有几十万行的数据,希望可以将表中重复内容删除,并将内容分离为每个Excel文件5000行数据。然后就有了这个测试,也许是因为思维发散的缘故,不知道,怎么的,就转到了处理从Excel文件中读取图片上来,事情的发展出乎我的意料,看来不够专注,不过这也让我有了意外的收获。

经过分析得出,不管是采用OleDbConnection还是采用Application对象,都是一样的需要加载Excel文件(纯粹废话),首先来了一段OleDbConnection读取的代码。

代码
string connection =string.Format("Provider=Microsoft.Jet.OLEDB.4.0;DataSource={0};Extended Properties=Excel 8.0;", FilePath);
OleDbConnection conn
=new OleDbConnection(connection);
conn.Open();
DataTable=conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, newobject[] {
null,null, null, "Table" });

 

上面的代码读取了在某个excel文件中存在所有工作簿,实际上是获取了excel文件的架构,即Sheet,这样可达到动态读取excel文件中所有内容的目的。

再看如何填充

代码
for(int i =0; i < dt.Rows.Count; i++)
{
Stringtext
=string.Format("selec*from {0}", dt.Rows[i]["TABLE_NAME"]);
OleDbDataAdaptermyCommand
=new OleDbDataAdapter(text,connection);
DataSetmyDataSet
=new DataSet();
myCommand.Fill(myDataSet);
}

上面的代码是把所有工作簿都填充为一个DataSet,这里仅作演示,因为我知道我的excel文件只有一个工作簿,当然实际中我们会分开的填充的。填充完毕后,我打开数据集一看,我被震精了,数据集中只有字符串内容,而并没有图片。这相当让我崩溃。

再换一个角度,用com对象来读取,思路和上面的一致,加载Excel文件,读取字符串数据。

 

代码
Excel.Application excel =new Excel.Application();
Excel.Workbook workbook
= excel.Workbooks.Add(filePath);
excel.UserControl
=true;
excel.Visible
=false;
for (int i =0; i < workbook.Worksheets.Count; i++)
{
System.Text.StringBuilder sb
=new System.Text.StringBuilder();
Excel.Worksheet sheet
= workbook.Worksheets.get_Item(i +1) as Excel.Worksheet;
for (int row =2; row <= sheet.UsedRange.Rows.Count; row++)
{
//取单元格值;
for (int col =1; col <= sheet.UsedRange.Columns.Count; col++)
{
Microsoft.Office.Interop.Excel.Range range
= sheet.Cells[row, col] as Excel.Range;
sb.Append(
","+ col.ToString() +":"+ range.Text);
}
sb.Append(System.Environment.NewLine);
Console.WriteLine(sb.ToString());
//取存图片;
if (sheet.Shapes.Count >0)
{
Bitmap picture;
IDataObject data
=null;
foreach (Excel.Shape item in sheet.Shapes)
{
item.Copy();
data
= Clipboard.GetDataObject();
if (null!= data)
{
picture
= (Bitmap) data.GetData(DataFormats.Bitmap);
picture.Save(
string.Format(@"D:\temp\aa\{0}.jpg", row));
}
}
}
}
}
workbook.Close(
false, null, null);
excel.Quit();

 

 

上面的代码是达到了读取数据和图片的要求,可实在是太慢,特别是对图片的读取上,这对内存一来一往的Copy和Paste,着实让我无法忍受,明明想要的东西就在眼前,这还要跑两次内存读取,相当的无语。

再次调试,显示IL后发现,我决定使用Shape.CopyPicture()方法,因为我发现Copy和CopyPicture方法实际上调用的是不同的实现,Copy是不管你是什么东西,一概Copy到内存中,CopyPicture则是可以按照一定的外观和格式Copy过去,当然,原理上说,应该是Copy速度更快一些。

曾经冒出过一个 极其可笑兼常用的方式,直接把IComObject对象转换为托管对象,如下:

IDataObject data=null;
Bitmapimg
=(Bitmap)data

 

这里直接失败,别说运行,编译都不通过。

再又冒出了一个把对象序列化流的想法,希望流的速度快些,结果发现Shape对象不支持序列化,意思是这条路也走不通了,最后看来,目前只能使用内存复制粘贴的方式来执行了。好吧,我还不相信没有别的办法了,等下回我再来收拾你。

posted @ 2010-01-08 14:53  Ron.Liang  阅读(2152)  评论(4编辑  收藏  举报