OleDb 内存泄露问题 本帖最后由 Suriyel 于 2014-06-20 02:10:47 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 郑笑彬 08:35:05 public DataSet ImportFromExcel(string FilePath) { System.Data.DataTable dt = new System.Data.DataTable(); ArrayList TablesList = new ArrayList(); System.Data.DataSet ds = new DataSet(); OleDbConnection dbcon = null; Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application(); string ss = excelApp.Version; switch (ss) { case "12.0": dbcon = new OleDbConnection("Provider=Microsoft.ACE." + "OLEDB.12.0;Extended Properties=\"Excel 8.0\";Data Source=" + FilePath); break; default: dbcon = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + FilePath + ";Extended Properties=Excel 8.0"); break; } try { TablesList = GetExcelTables(FilePath); try { for (int i = 0; i < TablesList.Count; i++) { string str = "select * from [" + TablesList[i] + "$]"; System.Data.DataTable table; OleDbCommand cmd = new OleDbCommand(str, dbcon); OleDbDataAdapter adapter = new OleDbDataAdapter(cmd); table = new System.Data.DataTable(TablesList[i].ToString()); adapter.Fill(table); ds.Tables.Add(table); } } catch (Exception exp) { MessageBox.Show(exp.Message, "读取EXCEL工作簿出错"); } } finally { } return ds; }使用Microsoft.Office.Interop.Excel.Apllication可以直接读取整个文档到dataset啊也可以指定单个sheet读取到datatable怎么可能只能按Range读取呢 从代码上来看,好像你只用application判断了下Excel版本,还是使用的oledb进行Excel数据读取,那么还是会有内存泄露问题。 NPOI呢?额,我们这边对开源项目审核的比较厉害,所以能不用开源的尽量没有用,哎 private static void KillExcel() { Process killer = new Process(); try { foreach (Process thisproc in Process.GetProcessesByName("EXCEL")) //循环查找 { string str = thisproc.MainWindowTitle; //发现程序中打开跟用户自己打开的区别就在这个属性 //用户打开的str 是文件的名称,程序中打开的就是空字符串 if (string.IsNullOrEmpty(str)) { thisproc.Kill(); } } } catch { string msg = "关闭失败"; MessageBox.Show(msg); } }有没有看进程里是否多了很多EXCEL进程?每次操作完杀死多余的没有界面的EXCEL进程试试. 我回复的就是针对:2,直接使用Microsoft.Office.Interop.Excel.Apllication进行Excel操作,并在操作后直接杀掉Excel进程。但是该方法因为Microsoft.Office.Interop.Excel.Apllication进行Excel读取,每个Range每个Range的读取,都是进程间进行数据交换,性能太渣。唯一可行的是,一大块一大块的读数据,但是没有找到对应的方法可以整个文档读取啊. 谢谢你的回复,这贴的关键讨论点,就是使用OleDb会导致内存泄露,这就是我使用application而不使用OleDb(你贴的代码里使用的方式)的原因,您贴的这个第2点,是在这个基础上说,application操作Excel性能消耗太大,不可用。我希望的是能够解决OleDb的内存泄露,但是您代码里直接使用的是OleDb,是不能解决这个问题的。 理下楼主的主要需求1,不能直接在当前进程中进行OleDb读取Excel。因为按楼主说的,OleDb存在内存泄露。那么解决思路应该有以下几个方向:1,能否用其他的方法进行Excel的读取。2,能否再其他进程进行Excel的读取,然后将结果传给当前进程。思路1,要么使用开源的Excel读取程序,要么使用Excel的Application,但按楼主的意思,这两个都不行。那么只能采用第2种思路了。对于思路2,最关键的应该是,采用什么的形式将结果传给当前进程。需要注意以下的约束:1,是否需要考虑较大的Excel文件。2,是通过进程间通信传,还是通过转为文本,主程序读取获得。考虑到以上的约束,我建议楼主另外开个进程,使用OleDb把Excel里所需的数据,转为csv或者txt,主线程可以使用Reader逐行读取解析。既可以规避你说的内存泄露问题,又最大限度的不影响性能和内存开销。 刚做了ADODB读取EXCEL功能,可以将EXCEL当数据库读数据库连接串就是版本号那一套,跟OLEDB一样用户名密码为空唯一缺点就是必须事先知道Sheet名称或者可以用第三方插件,比如NOPI? 就是ADO,OleDb读取Excel,存在内存泄露啊,你用一个大一点的Excel,只是Open再Close试试,内存是没有回退到原有水平的,调了Gc都没用。我感觉Shannon的方法比较可行。 这个是老毛病了,换个高版本的,或者把excel文件先改成只读,再读取,然后改回来就行了 改成只读,内存还是有泄露啊换个高版本指的的是Framework还是office? 还是改用NPOI算了,还方便,不用考虑用户安装的OFFICE版本,也不用考虑用户是否用的WPS http://club.excelhome.net/thread-464455-1-1.html或者Provider=Microsoft.ACE.OLEDB.12.0试试吧 很明显,如果你搞不明白基本概念,那么就算你瞎用什么软件来代替,都脱离不了基本的托管程序系统的内存分配策略的制约。不管用什么PPOO的软件,你都会说它“内存泄露”的。而且另一个问题是,不管用什么软件,如果你要在内存里将多个 900M 的Excel文件内容同时读取到内存里,都一样会崩溃。 c# 调用 jTTS_ML.dll,老是报错! 用webbrowser做的浏览器,怎么弄收藏夹下拉菜单 NTEXT字段的数据查重可以用SQL语句实现吗?[50分加急] 急急急!!!!!! 在web客户端如何对TreeView 进行初始话? 如何捕获textbox的变化,但是不需要刷新就能对此做出反应 怎么用HttpWebRequest以get方式提交呢? remoting假死的问题 请教一个GDI消锯齿的问题 如何在c#里通过变量来打开窗体 如何把菜单加入IE右键菜单里 无法解决这问题就怒挂东南枝了 datagrid 刷新问题
郑笑彬 08:35:05
public DataSet ImportFromExcel(string FilePath)
{
System.Data.DataTable dt = new System.Data.DataTable();
ArrayList TablesList = new ArrayList(); System.Data.DataSet ds = new DataSet(); OleDbConnection dbcon = null;
Microsoft.Office.Interop.Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
string ss = excelApp.Version;
switch (ss)
{
case "12.0":
dbcon = new OleDbConnection("Provider=Microsoft.ACE." + "OLEDB.12.0;Extended Properties=\"Excel 8.0\";Data Source=" + FilePath);
break;
default:
dbcon = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + FilePath + ";Extended Properties=Excel 8.0");
break;
} try
{
TablesList = GetExcelTables(FilePath); try
{
for (int i = 0; i < TablesList.Count; i++)
{
string str = "select * from [" + TablesList[i] + "$]"; System.Data.DataTable table; OleDbCommand cmd = new OleDbCommand(str, dbcon);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
table = new System.Data.DataTable(TablesList[i].ToString()); adapter.Fill(table);
ds.Tables.Add(table);
}
}
catch (Exception exp)
{
MessageBox.Show(exp.Message, "读取EXCEL工作簿出错");
}
}
finally
{
}
return ds;
}
使用Microsoft.Office.Interop.Excel.Apllication可以直接读取整个文档到dataset啊
也可以指定单个sheet读取到datatable
怎么可能只能按Range读取呢
额,我们这边对开源项目审核的比较厉害,所以能不用开源的尽量没有用,哎
{
Process killer = new Process();
try
{
foreach (Process thisproc in Process.GetProcessesByName("EXCEL")) //循环查找
{
string str = thisproc.MainWindowTitle; //发现程序中打开跟用户自己打开的区别就在这个属性
//用户打开的str 是文件的名称,程序中打开的就是空字符串
if (string.IsNullOrEmpty(str))
{
thisproc.Kill();
}
}
}
catch
{
string msg = "关闭失败";
MessageBox.Show(msg);
}
}
有没有看进程里是否多了很多EXCEL进程?每次操作完杀死多余的没有界面的EXCEL进程试试.
2,直接使用Microsoft.Office.Interop.Excel.Apllication进行Excel操作,并在操作后直接杀掉Excel进程。
但是该方法因为Microsoft.Office.Interop.Excel.Apllication进行Excel读取,每个Range每个Range的读取,都是进程间进行数据交换,性能太渣。唯一可行的是,一大块一大块的读数据,但是没有找到对应的方法可以整个文档读取啊.
谢谢你的回复,这贴的关键讨论点,就是使用OleDb会导致内存泄露,这就是我使用application而不使用OleDb(你贴的代码里使用的方式)的原因,您贴的这个第2点,是在这个基础上说,application操作Excel性能消耗太大,不可用。我希望的是能够解决OleDb的内存泄露,但是您代码里直接使用的是OleDb,是不能解决这个问题的。
1,不能直接在当前进程中进行OleDb读取Excel。因为按楼主说的,OleDb存在内存泄露。
那么解决思路应该有以下几个方向:
1,能否用其他的方法进行Excel的读取。
2,能否再其他进程进行Excel的读取,然后将结果传给当前进程。思路1,要么使用开源的Excel读取程序,要么使用Excel的Application,但按楼主的意思,这两个都不行。
那么只能采用第2种思路了。对于思路2,最关键的应该是,采用什么的形式将结果传给当前进程。
需要注意以下的约束:
1,是否需要考虑较大的Excel文件。
2,是通过进程间通信传,还是通过转为文本,主程序读取获得。考虑到以上的约束,我建议楼主另外开个进程,使用OleDb把Excel里所需的数据,转为csv或者txt,主线程可以使用Reader逐行读取解析。既可以规避你说的内存泄露问题,又最大限度的不影响性能和内存开销。
数据库连接串就是版本号那一套,跟OLEDB一样
用户名密码为空
唯一缺点就是必须事先知道Sheet名称或者可以用第三方插件,比如NOPI?
改成只读,内存还是有泄露啊
换个高版本指的的是Framework还是office?
Provider=Microsoft.ACE.OLEDB.12.0试试吧