说到Excel的导入,其实最根本的需求还是对Excel文档的解析,现在主要的Excel文档解析方法主要有两种,OleDb直接对Excel数据源进行解析或就是使用Excel的类库对ExcelApplication进行操作
在网上有很多介绍如何使用OleDb利用SQL读取Excel数据源的介绍,这样做最大的好处就是方便,大家可以直接使用SQL对Exce中指定的文档,指定的区域l进行查询,但是缺点也很明显:
1.数据格式限制
既然将Excel作为数据源读取,那么对读取的数据源就有了一定的数据格式限制:如:在使用IMEX=1的设定时,如果列中包含多种不同的数据格式的数据,默认一部分数据的格式会被转化为另一部分数据的格式:体验最明显的就是对日期的处理,如果一列中包含大量的整数数据,那么这一列的日期会被转化为格林威治的整数时间,如果该列包含大量的字符串类型的数据,那么日期又会被转化为字符串格式,也就是说IMEX=1并非严格按照混合列传成字符串来进行处理的,这也许和Excel对日期的处理有关。如果在使用HDR=YES的设定时,如果列头包含日期格式的数据是无法被是被出来的
2.功能限制
将Excel作为数据源进行读取则势必会抛弃Excel对单元格的处理功能,如判断颜色,单元格十分合并等等OleDb肯定是做不到的,也不是OleDb的发展方向
综上,使用OleDb方式对数据库进行读取虽然很方便且效率相对较高,但是存在一定的不安全性,对数据的读取能力也有限,有时还要配合注册表的更改一起使用,所以直接使用Excel.dll提供的方法进行Excel的操作还是有很大的用处的。下面对Excel.dll包对Excel读取进行简要介绍
使用ExcelApp进行Excel连接的基本代码为:
//获取进程创建开始时间
startTime = DateTime.Now;
Excel.Application excel = new Application();
//获取进程创建结束时间
endTime = DateTime.Now;
object missing = System.Reflection.Missing.Value;
//只读打开工作表
Workbook wb = excel.Application.Workbooks.Open(path, missing, true, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing);
//打开第一个工作簿
ws = (Excel.Worksheet)wb.Worksheets.get_Item(1);
使用该包读取Excel主要会遇到以下几个问题:
1.Range
Range是Excel.dll进行数据读取的常用单位,相比Cell来说,Range的功能更为强大,比如合并单元格等等
//得到指定区域的Range
ws.get_Range("A1",Missing.Value).Text;
ws.get_Range("A1", "C3").Text;
//使用坐标得到Range(Cell)
((Range)ws.Cells[rowIndex, columnIndex]).Text
//使用Range判断是否为合并单元格
nowRange.MergeArea.Value;
//获得合并单元格列数
nowRange.MergeArea.Columns.Count;
//获得合并单元格行数
nowRange.MergeArea.Rows.Count;
//获得Excel中已使用单元格
//(如果在单元格中只删除数据,没有进行全部清除,则没有数据的单元格也会被取到)
ws.UsedRange.Columns.Count;
2.进程的释放
才用ExcelApp进行释放的效率和可靠性往往不能令人满意,往往会造成系统中存在大量的EXCEL进程不能得到有效释放,解决这个问题最直接的方法是将进程Kill掉,但是在创建Excel进程时无法指定进程ID,所以最后折中的办法是不活ExcelApp创建的时间区间,使用Process将在该时间区间内创建的Excel进程Kill掉,这样有可能会错杀无辜,但是由于进程的创建是毫秒级的,所以在并发量较小的企业内部信息系统中还是可以接受的,具体代码为
Process[] processArr = Process.GetProcessesByName(ProcessName);
foreach (var process in processArr)
{
if (process.StartTime > startTime && process.StartTime < endTime)
{
//关闭当前进程
process.Kill();
}
}
补充:
经过最新的测试发现了如下问题:
1.process.StartTime > startTime && process.StartTime < endTime本句有毛病,如果进程创建过快,开始和结束时间可能会捕获为相同,应该修改为process.StartTime >= startTime && process.StartTime <= endTime,
DateTime.Now的判等精度:
1.MSDN上说:DateTime.Now此属性的分辨率取决于系统计时器,其实这主要是在Wince上会有所不同,按MSDN的说法Wince取得Now仅得到秒级
其实,==的判等应该和Equal相同,Equal方法使用的是属性Ticks进行判等,Ticks精确到一百纳秒,即一千万分之一秒,可以得出,Now的取值精度也是一千万分之一秒
2.Process的Kill方法是异步的,也就是说进程没有立即被释放掉,可以使用process.WaitForExit(),使当前进程阻塞,直至Kill执行完毕
综上,修改过的代码应为
Process[] processArr = Process.GetProcessesByName(ProcessName);
foreach (var process in processArr)
{
if (process.StartTime >= startTime && process.StartTime <= endTime)
{
//关闭当前进程
process.Kill();
process.WaitForExit();
}
}