新的项目,新的内容:原本计划中使用的复杂数据库,连同其已经编好存储过程一起随着需求的改变,统统的不要了,虽然白忙一场,但也学到不少知识,特别是oralce存储过程的使用以及C#的调用。现在呢,将要采用Exlcel来代替数据库,进行数据的访问。
言归正传,.Net要访问Excel有2个途径:
1、通过引用Office的接口访问:
using Microsoft.Office.Interop.Excel;
2、通过Ado.Net访问:
using System.Data.Odbc;
现在就我项目中所要做的事情进行说明:首先要创建Excel,其次新建Sheet,然后给Excel文件创建第一行(相当于数据库的字段),接着要开始对Sheet的内容进行查插删改。其整个过程就是简化版的数据库的新建,表的新建,数据的查插删改等数据库基本操作。
下面,按照这个流程,我来贴出我的测试代码,并解释:
为了便于理解,我建立了下面的变量:
Microsoft.Office.Interop.Excel.Application app;
string DataFileDir = @"C:\WuxiZb";
string DataFilePath = @"C:\WuxiZb\SortPlan_Zb.xls";
string FilePassWord = "";
我实验时,由于多次开启Excel 的Application,导致任务管理器中发现了N个名为Excel的进程,幸亏我发现了网上的这段代码,真的很重要,在程序初始化时执行:
Code
System.Diagnostics.Process[] arrProcesses;
arrProcesses = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process myProcess in arrProcesses)
{
myProcess.Kill();
}
app = new Microsoft.Office.Interop.Excel.Application();
还有网上的这段资源的释放也是必备的:
Code
private void ReleaseCOM(object pObj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(pObj);
}
catch
{
throw new Exception("释放资源时发生错误!");
}
finally
{
pObj = null;
}
}
以下记得在系统退出时执行:
//释放资源
app.Quit();
ReleaseCOM(app);
好,正式工程开始了:
首先创建新的工作表:
Code
Workbooks wbs = app.Workbooks;
Workbook wb = wbs.Add(true);//新增一个的工作薄
try
{
wb.SaveAs(DataFilePath, XlFileFormat.xlAddIn, FilePassWord, Missing.Value, false, false, XlSaveAsAccessMode.xlExclusive, XlSaveConflictResolution.xlUserResolution, false, Missing.Value, Missing.Value, true);
}
catch { }
//关闭并释放资源
wb.Close(true, DataFilePath, false);
ReleaseCOM(wb);
ReleaseCOM(wbs);
其中,SaveAs的具体的参数说明,msdn一下吧,很详尽的。这个函数还能给工作表加密哦,不过,因为加了密码后无法odbc访问了,所以这里就是用空密码了。
好,“数据库”建完了,有了个空“表”了,下面我们需要自定义了“表”了:
Code
Workbooks wbs = app.Workbooks;
Workbook wb = wbs.Open(DataFilePath, 3, false, 5, FilePassWord, Missing.Value, true, XlPlatform.xlWindows, Missing.Value, false, true, Missing.Value, false, true, Missing.Value);//打开一个现有的工作薄
Sheets shs = wb.Sheets;
//修改第一Sheet
Worksheet wsh;
wsh = (Worksheet)shs[1];
wsh.Name = "中心局";
//新增第二Sheet
wsh = (Worksheet)shs.Add(Missing.Value, shs[shs.Count], 1, XlSheetType.xlWorksheet);
wsh.Name = "区县局";
//关闭并释放资源
wb.Save();
wb.Close(true, DataFilePath, false);
ReleaseCOM(wb);
ReleaseCOM(wbs);
恩恩,就是这样,如果是像网上那样用Add来打开现有表的话,表名可是真的名字后面追加数字的,例如“测试1”,“测试2”,这样子,Save就是问题了。
下面我们再来看看这种模式下单元格的操作(相当于创建表列与初始的数据)
首先来看看删除“表”:
Code
Workbooks wbs = app.Workbooks;
Workbook wb = wbs.Open(DataFilePath, 3, false, 5, FilePassWord, Missing.Value, true, XlPlatform.xlWindows, Missing.Value, false, true, Missing.Value, false, true, Missing.Value);//打开一个现有的工作薄
Sheets shs = wb.Sheets;
Worksheet sh = (Worksheet)shs[shs.Count];
//删除测试
sh.Delete();
下面可以修改单元格了:
Code
//修改单元格测试
sh.Cells[1, 1] = "第一行第一列";
//修改选中区域测试
//单个单元格
Range range;
range = sh.get_Range("H1", Missing.Value);
range.Value2 = new int[] { 20 };
//range = sh.get_Range(Missing.Value, "H2");//此句会失败
//range.Value2 = new int[] { 30 };
range = sh.get_Range("H3", "H3");
range.Value2 = new int[] { 40 };
//多个单元格
range = sh.get_Range("A2", "A6");
int[] value=new int[] { 1, 2, 3, 4, 5 };
//range.Value2 = value;//此句执行后,所有的值都赋成了数组第一个数
for (int i = 0; i < 5; i++)
{
range[i + 1, 1] = value[i];
}
string[] value2 = new string[] { "01", "02"," 3", "4 x", "5 " };
range = sh.get_Range("B1", "f1");//小写字母有效
range.Value2 = value2;//横向此类赋值,有效
range = sh.get_Range("A6", "IV6");//选中一行,256个
range.Delete(XlDeleteShiftDirection.xlShiftUp);
里面函数的参数请查阅msdn,我也是看那里看来得
下面问题产生了,如果要批量修改数据,这么做太慢了!
好吧,现在是ADO.Net出场的时候了:
不过呢由于Excel是没有主键的,所以CommandBuilder还是不要想了,语句自己来吧
Code
string connString = String.Format("Dsn=Excel Files;dbq={0};defaultdir={1};driverid=1046;maxbuffersize=2048;pagetimeout=5;", pPath, DataFileDir);
OdbcConnection conn = new OdbcConnection(connString);
string sheetName = "中心局";
string tableNmae="[" + sheetName.Replace('.', '#') + "$]";
string sql = "select * from " + tableNmae;
OdbcDataAdapter da = new OdbcDataAdapter(sql, connString);
DataSet ds = new DataSet();
System.Data.DataTable dt;
try
{
da.Fill(ds);
dt = ds.Tables[0];
dataGridView1.DataSource = dt;
//ds.Tables[0].PrimaryKey = new DataColumn[] { dt.Columns[0] };
//string delIndex = "V";
//update测试:成功
//da.UpdateCommand = new OdbcCommand(string.Format("update {0} set 中心局名称='Z' where 中心局名称='{1}'", tableNmae, delIndex), conn);
//dt.Select(string.Format("中心局名称='{0}'", delIndex))[0]["中心局名称"] = "Z";
//insert测试:成功
//da.InsertCommand = new OdbcCommand(string.Format("insert into {0} (中心局名称) values('{1}')", tableNmae, "016"), conn);
//DataRow newCode = dt.NewRow();
//newCode["中心局名称"] = "New";
//dt.Rows.Add(newCode);
//deltete测试:ADO Excel不支持Deltete
//dt.Select(string.Format("中心局名称='{0}'", delIndex))[0].Delete();
//da.DeleteCommand=new OdbcCommand (string.Format("delete from {0} where 中心局名称='{1}'",tableNmae,delIndex),conn);
da.Update(dt);
return ds.Tables[0];
}
catch(Exception ex)
{
ds = null;
string msg = ex.Message;
return null;
}
finally
{
ds.Dispose();
da.Dispose();
}
这样一来,大家可以看到:查询、插入、修改都OK了,但是删除失败了。那怎么办啊?如果只是把只update为null叫什么delete啊,而且造成n多的空白行!
其实,如果您仔细看我前面的代码,会发现,其实Delete在那里已经操作过了,对了就是这里:
range = sh.get_Range("A6", "IV6");//选中一行,256个
range.Delete(XlDeleteShiftDirection.xlShiftUp);
现在,您所要做的就是用ADO找到sel到要删除的行号,然后如此删除整行即可,其中Delete的参数我选择了“下边的单元格向上移”。
ok,至此,“数据库”的新建;“表”的新建、删除;“数据”的查插删改,都可以了,怎么样,下面等着的就是实际应用了!
最后附上我的测试电子表格的样子:
给出例子的下载地址:http://download.csdn.net/source/1761945