我尝试了很多解决方案,但没有工作请帮我解决这个问题。 以下是 SSIS脚本任务
中使用的代码 using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlApp = null;
Excel.Workbooks workbooks = null;
Excel.Workbook xlWorkbook = null;
Excel.Worksheet worksheet = null;
Excel.Range xlRange = null;
try
{
xlApp = new Excel.Application();
xlApp.DisplayAlerts = false;
xlApp.AskToUpdateLinks = false;
workbooks = xlApp.Workbooks;
xlWorkbook = workbooks.Open("sample.csv", 2, true);
xlWorksheet = xlWorkbook.Sheets[1];
xlRange = xlWorksheet.UsedRange;
int rowCount = xlRange.Rows.Count;
for (int row = 2; row <= rowCount; row++)
{
//some logic
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally //releasing all resources
{
GC.Collect();
GC.WaitForPendingFinalizers();
Marshal.ReleaseComObject(xlRange);
Marshal.ReleaseComObject(xlWorksheet);
xlRange = null;
xlWorksheet = null;
xlWorkbook.Close();
Marshal.ReleaseComObject(xlWorkbook);
xlWorkbook = null;
workbooks = null;
xlApp.Quit();
Marshal.ReleaseComObject(xlApp);
xlApp=null;
}
即使在发布资源后,仍然会看到一个excel进程
答案 0 :(得分:1)
有两种方法可以实现这一目标:
第一种方法
您可以创建自定义ReleaseObject
功能,如下所示:
private void ReleaseObject(object obj)
{
try {
int intRel = 0;
do {
intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
} while (intRel > 0);
} catch (Exception ex) {
obj = null;
} finally {
GC.Collect();
}
}
并使用以下代码顺序:
xlWorkBook.SaveAs("....");
xlWorkBook.Close();
xlApp.Quit();
ReleaseObject(xlRange);
ReleaseObject(xlWorkSheet);
ReleaseObject(xlWorkBook);
ReleaseObject(xlApp);
第二种方法
在脚本任务中创建一个类,创建一个获取Excel.Application
的进程ID并将其终止的函数
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
using System.Diagnostics;
class Sample
{
[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
Process GetExcelProcess(Excel.Application excelApp)
{
int id;
GetWindowThreadProcessId(excelApp.Hwnd, out id);
return Process.GetProcessById(id);
}
}
然后您可以使用GetExcelProcess(XlApp).Kill();
答案 1 :(得分:0)
看起来你走在正确的轨道上。但是,您现在是ExcelApplication,它是您在任务监视器中看到的实际进程,以及需要在WordApplication被杀死之前关闭的ExcelDocument。
看看这个简单的例子:
public void Foo(string filePath)
{
var application = new Excel.Application();
// do your stuff here...
var document = application.Workbooks.Open(filePath, ReadOnly: true, Visible: false);
// this is the magic: clear 'application' and 'document',
// once the work is finished
if (document != null)
document.Close(SaveChanges: false);
if (application != null)
application.Quit(SaveChanges: false);
document = null;
application = null;
}
在这里,您会看到我们实际上正确关闭()工作簿(文档)和退出()应用程序。这有点与你在finally部分中所做的有关,但请记住,变量在之前初始化,你可以进入try ...部分。
我的建议:不要手动调用任何垃圾收集(GC)和Marshal东西。如果你不确定它做了什么,以后会因为副作用而伤害你。接下来,您可以通过在ExcelApplication和ExcelWorkbook周围添加一个漂亮的using (...)
结构来进一步改进示例。
答案 2 :(得分:0)
正确清理Interop.Excel
个物件很难。做错了,你可以用大量的Excel僵尸实例来破坏SQL或SSIS机器。
互联网是littered with advice,关于如何正确Close()
,Quit()
,ReleaseObject()
Interop.Excel
个对象。适合您的建议取决于您调用对象的顺序以及您调用的方法。例如,如果您使用double dot method,那么您创建了一个不可关闭的对象。即使您注意到所有建议并构建代码以避免陷阱,当SSIS包部署到服务器时,事情也会发生变化。微软基本上已经告诉开发人员not do this。
Microsoft目前不建议也不支持从任何无人参与的非交互式客户端应用程序或组件(包括ASP,ASP.NET,DCOM和NT服务)自动化Microsoft Office应用程序,因为Office可能会出现不稳定Office在此环境中运行时的行为和/或死锁。
奇怪的事情发生了。而且,它不会扩展。包将共享相同的Excel实例。一个包的清理程序可以杀死另一个包的飞行操作。
听着,我知道Interop.Excel
上有很多关于如何清除的方法,以及如何清理它们的方法。但是,这些文章针对的是在自己的机器上运行单个代码实例的个人。没有建议使用SSIS的企业环境。是的,这很臭。
但是,有解决方案! NetOffice类似于Interop.Excel
,有助于处理COM对象的关闭和处理。我的强烈偏好是EPPlus API它非常轻量级,类似于Interop.Excel
,并且在没有清理困难的情况下快10倍。除了打印和宏之外,它几乎可以完成Interop所能做的一切。甚至比C#更好的是开始使用built-in SSIS Excel components微软提供的ETL工作。