Microsoft Excel 无法访问 Windows Server 2012 上的文件
Microsoft Excel cannot access the file on Windows Server 2012
我正在 运行安装一个包含 C# 脚本的 SSIS 包,该脚本在 Windows Server 2012 R2 上格式化 Excel 文件。
当我 运行 包时它给我这个错误 Microsoft Office Excel 无法访问文件 '\\FolderPath\FilePath'
我看过这个问题 Microsoft Office Excel cannot access the file 'c:\inetpub\wwwroot\Timesheet\App_Data\Template.xlsx' 并检查了我的许可,它们是正确的。
我也试过在最终文件路径周围添加 双引号 sFile = "\"" + sFile + "\"";
但这会输出错误 Microsoft Excel cannot访问文件'"\FolderPath\FilePath"它正在删除一个\我真的不明白为什么。
下面是原代码
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Data.SqlClient;
using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Reflection;
public int Main()
{
StringBuilder sb = new StringBuilder();
string LogFilePath = "\\LogFilePath";
string strExcelDataOutPut = "\\FolderPath";
string sPath = "\filePath";
try {
FormatFile(strExcelDataOutPut,sPath);
} catch (Exception ex) {
using (System.IO.StreamWriter outfile = new System.IO.StreamWriter(LogFilePath))
{
sb.AppendLine("Error Occured ..Please see the error Message :" + ex.Message);
outfile.Write(sb.ToString());
}
}
}
public void FormatFile(string strExcelDataOutPut, string sPath)
{
Microsoft.Office.Interop.Excel.Application objExcelApp = new Excel.Application();
Microsoft.Office.Interop.Excel.Workbook objExcelWbk = default(Excel.Workbook);
Microsoft.Office.Interop.Excel.Worksheet objWrksheet = default(Excel.Worksheet);
object missing = Missing.Value;
Excel.Range crange1;
string sFile = string.Empty;
string sWorkSheet = string.Empty;
//--Month in English/French
string sMonthYear = string.Empty;
try
{
objExcelApp.DisplayAlerts = false;
objExcelApp.Visible = false;
sFile = strExcelDataOutPut + sPath;
//--Check if the file exists ---------------------------------------------------------
if (System.IO.File.Exists(sFile))
{
sWorkSheet = "Sheet1";
}
objExcelWbk = objExcelApp.Workbooks.Open(sFile.Trim(), missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, true);
objWrksheet = (Excel.Worksheet)objExcelWbk.Worksheets[sWorkSheet];
((Microsoft.Office.Interop.Excel._Worksheet)objWrksheet).Activate();
//--Format
sMonthYear = "Report as at: " + DateTime.Today.ToString("MMMM") + " " + DateTime.Today.Day.ToString() + ", " + DateTime.Today.Year.ToString();
objWrksheet.PageSetup.LeftHeader = "&8&F";
//objWrksheet.PageSetup.CenterFooter = @"&12&""Arial,Bold" + sMonthYear;
objWrksheet.PageSetup.CenterFooter = " " + sMonthYear;
crange1 = (Excel.Range)objWrksheet.Cells[1, 1];
crange1.Select();
//objExcelWbk.SaveAs(sFile, missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, missing, missing, missing, missing, missing);
//objExcelWbk.Close(true, missing, missing);
objExcelWbk.Save();
objExcelWbk.Close(true, sFile, missing);
objExcelApp.Quit();
}
catch
{
throw;
}
finally
{
objWrksheet = null;
objExcelWbk = null;
objExcelApp = null;
System.GC.Collect();
}
}
该代码对于 Internet 而言似乎过于净化,因为它似乎与您的文件工作不符。
C# 观察结果
转义斜线是非常痛苦的,因为它也发出控制字符的信号。 C# 允许您指示字符串是 verbatim string 然后您不必处理转义所有内容。
在你的 Main 中,你有
string strExcelDataOutPut = "\\FolderPath";
string sPath = "\filePath";
评估这些字符串时,您将获得 \FolderPath
和 \filePath
的值
您在方法调用中将它们合并为
sFile = strExcelDataOutPut + sPath;
生成一个 UNC 路径 \FolderPath\filePath
很好,但这不是文件名。您似乎缺少实际的文件名,例如
sFile = strExcelDataOutPut + sPath + @"\Something.xlsx";
我有一个组合路径以创建有效路径的技巧 - 有一个库和方法可以做到这一点。 System.IO.Path.Combine 它非常好,因为您不必为那里的值做太多的转义。
sFile = Path.Combine(strExcelDataOutPut, sPath, "Something.xlsx");
如果找到文件,您对文件是否存在的检查会设置工作表名称,但如果找不到文件,则不执行任何操作。当您尝试打开不存在的文件时,这不会导致问题吗?或者,如果 Excel 将创建文件,那么当您尝试访问 Worksheets 集合中名为(空字符串)的工作表时,将会失败。
最后,请注意在您的方法中使用 double dots。
SSIS 观察结果
你没有指定你在哪里 运行 这个包和遇到的问题,但我可以看到一些可能出错的地方。
首要的是许可。只要您、您的 DBA 和管理层了解此实施将要求您为 SQL 服务器实例购买 Microsoft Office 许可证。与典型的服务器级产品相比,Office 需要更频繁地打补丁并可能重新启动。这意味着如果您的 SQL 服务器安装有严格的 SLA,此实施可能会侵犯 window。
215 美元(CDW 对家庭和商业许可证的报价),我们的服务器现在更频繁地打补丁。太棒了,现在服务器 FolderPath 死了,或者文件共享发生了变化,或者发生了 任何事情,现在您需要更改该路径 - 您正在查看打开包,编辑脚本值,保存它,将其检查到版本控制中(你 做 使用版本控制,对吗?),然后将其提交到你的雇主拥有的任何变更控制过程中。在我的世界里浪费了很多时间。
相反,您可以
string LogFilePath = "\\LogFilePath";
string strExcelDataOutPut = "\\FolderPath";
string sPath = "\filePath";
变成类似
的东西
string LogFilePath = Dts.Variables["LogPath"].Value.ToString();
string strExcelDataOutPut = Dts.Variables["ExcelPath"].Value.ToString();
string sPath = Dts.Variables["FilePath"].Value.ToString();
那是什么让你?现在您 运行 您的脚本基于 SSIS 中的变量。您可以通过配置或参数化(取决于部署模型)对这些变量进行更改,然后您的包行为会发生变化而无需更改代码。您正在更新某个存储库中的外部值而不是代码本身。在我工作的环境中,与代码更改相比,实施更改通常风险要低得多(即使您所做的只是更改变量的值)。
除非您已经构建了一个进程来在那里使用您的自定义日志记录,否则请停止并使用 native tooling。引发信息、警告或错误消息。否则,您将需要确保 SSIS 可以写入该位置(稍后会详细介绍)。
Dts.Events.FireError(0, "Excel Writer", "Error Occurred...Please see the error Message :" + ex.Message, String.Empty, 0);
现在当您的包是 运行 时,该信息将转储到错误处理程序。如果您使用项目部署模型,该信息将自动记录到 SSISDB.catalog.operation_messages table 并显示在您的友好报告中。否则,转到 configure logging,SSIS 会将这些事件写入 table、平面文件、事件查看器、分析器 and/or 和 XML 文件。重要的是除非你有充分的理由,否则不要重新发明轮子。
当您使用 运行 此 SSIS 程序包时,您需要确保使用相对于 32 位或 64 位版本的 Office 而言正确的 dtexec 版本。这咬了很多人的屁股。 Office一般默认32位安装,有点可惜
当这个包运行时,即它在SQL服务器上运行,可能是SQL代理作业的一部分,运行 SQL 代理的帐户可能需要通常授予该帐户的更高级别的权限。它需要网络访问该文件共享到的任何地方。它将需要 InteractWithDesktop to be able to instantiate an instance of Excel and then do the needful. The SQL Agent job step will need to ensure that it has correctly flagged the SSIS package to be run as 32 bit 而不是 64(默认值)。如果您没有实现日志记录并且您没有使用项目部署模型,那么包会生成错误,错误消息将在 SQL 代理作业历史记录中捕获。这在某些时候会有用。
所以我遇到了这个 Microsoft Blog。虽然这很奇怪为什么你需要创建桌面文件夹但它有效。如果 link 被删除,请参阅下面的答案
分辨率
************ ·
C:\Windows\SysWOW64\config\ 中的“systemprofile”文件夹中似乎需要“桌面”文件夹才能打开 Excel 文件·
在位置 C:\Windows\SysWOW64\config\systemprofile 下为 Windows 2008 Server (x64) 创建“桌面”文件夹 ·
对于 32 位 Windows 2008 服务器,在位置 C:\Windows\System32\config\systemprofile ·
下创建“桌面”文件夹
创建文件夹后,SQL 服务器作业应该成功执行
我正在 运行安装一个包含 C# 脚本的 SSIS 包,该脚本在 Windows Server 2012 R2 上格式化 Excel 文件。
当我 运行 包时它给我这个错误 Microsoft Office Excel 无法访问文件 '\\FolderPath\FilePath'
我看过这个问题 Microsoft Office Excel cannot access the file 'c:\inetpub\wwwroot\Timesheet\App_Data\Template.xlsx' 并检查了我的许可,它们是正确的。
我也试过在最终文件路径周围添加 双引号 sFile = "\"" + sFile + "\"";
但这会输出错误 Microsoft Excel cannot访问文件'"\FolderPath\FilePath"它正在删除一个\我真的不明白为什么。
下面是原代码
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Data.SqlClient;
using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Reflection;
public int Main()
{
StringBuilder sb = new StringBuilder();
string LogFilePath = "\\LogFilePath";
string strExcelDataOutPut = "\\FolderPath";
string sPath = "\filePath";
try {
FormatFile(strExcelDataOutPut,sPath);
} catch (Exception ex) {
using (System.IO.StreamWriter outfile = new System.IO.StreamWriter(LogFilePath))
{
sb.AppendLine("Error Occured ..Please see the error Message :" + ex.Message);
outfile.Write(sb.ToString());
}
}
}
public void FormatFile(string strExcelDataOutPut, string sPath)
{
Microsoft.Office.Interop.Excel.Application objExcelApp = new Excel.Application();
Microsoft.Office.Interop.Excel.Workbook objExcelWbk = default(Excel.Workbook);
Microsoft.Office.Interop.Excel.Worksheet objWrksheet = default(Excel.Worksheet);
object missing = Missing.Value;
Excel.Range crange1;
string sFile = string.Empty;
string sWorkSheet = string.Empty;
//--Month in English/French
string sMonthYear = string.Empty;
try
{
objExcelApp.DisplayAlerts = false;
objExcelApp.Visible = false;
sFile = strExcelDataOutPut + sPath;
//--Check if the file exists ---------------------------------------------------------
if (System.IO.File.Exists(sFile))
{
sWorkSheet = "Sheet1";
}
objExcelWbk = objExcelApp.Workbooks.Open(sFile.Trim(), missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, true);
objWrksheet = (Excel.Worksheet)objExcelWbk.Worksheets[sWorkSheet];
((Microsoft.Office.Interop.Excel._Worksheet)objWrksheet).Activate();
//--Format
sMonthYear = "Report as at: " + DateTime.Today.ToString("MMMM") + " " + DateTime.Today.Day.ToString() + ", " + DateTime.Today.Year.ToString();
objWrksheet.PageSetup.LeftHeader = "&8&F";
//objWrksheet.PageSetup.CenterFooter = @"&12&""Arial,Bold" + sMonthYear;
objWrksheet.PageSetup.CenterFooter = " " + sMonthYear;
crange1 = (Excel.Range)objWrksheet.Cells[1, 1];
crange1.Select();
//objExcelWbk.SaveAs(sFile, missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, missing, missing, missing, missing, missing);
//objExcelWbk.Close(true, missing, missing);
objExcelWbk.Save();
objExcelWbk.Close(true, sFile, missing);
objExcelApp.Quit();
}
catch
{
throw;
}
finally
{
objWrksheet = null;
objExcelWbk = null;
objExcelApp = null;
System.GC.Collect();
}
}
该代码对于 Internet 而言似乎过于净化,因为它似乎与您的文件工作不符。
C# 观察结果
转义斜线是非常痛苦的,因为它也发出控制字符的信号。 C# 允许您指示字符串是 verbatim string 然后您不必处理转义所有内容。
在你的 Main 中,你有
string strExcelDataOutPut = "\\FolderPath";
string sPath = "\filePath";
评估这些字符串时,您将获得 \FolderPath
和 \filePath
您在方法调用中将它们合并为
sFile = strExcelDataOutPut + sPath;
生成一个 UNC 路径 \FolderPath\filePath
很好,但这不是文件名。您似乎缺少实际的文件名,例如
sFile = strExcelDataOutPut + sPath + @"\Something.xlsx";
我有一个组合路径以创建有效路径的技巧 - 有一个库和方法可以做到这一点。 System.IO.Path.Combine 它非常好,因为您不必为那里的值做太多的转义。
sFile = Path.Combine(strExcelDataOutPut, sPath, "Something.xlsx");
如果找到文件,您对文件是否存在的检查会设置工作表名称,但如果找不到文件,则不执行任何操作。当您尝试打开不存在的文件时,这不会导致问题吗?或者,如果 Excel 将创建文件,那么当您尝试访问 Worksheets 集合中名为(空字符串)的工作表时,将会失败。
最后,请注意在您的方法中使用 double dots。
SSIS 观察结果
你没有指定你在哪里 运行 这个包和遇到的问题,但我可以看到一些可能出错的地方。
首要的是许可。只要您、您的 DBA 和管理层了解此实施将要求您为 SQL 服务器实例购买 Microsoft Office 许可证。与典型的服务器级产品相比,Office 需要更频繁地打补丁并可能重新启动。这意味着如果您的 SQL 服务器安装有严格的 SLA,此实施可能会侵犯 window。
215 美元(CDW 对家庭和商业许可证的报价),我们的服务器现在更频繁地打补丁。太棒了,现在服务器 FolderPath 死了,或者文件共享发生了变化,或者发生了 任何事情,现在您需要更改该路径 - 您正在查看打开包,编辑脚本值,保存它,将其检查到版本控制中(你 做 使用版本控制,对吗?),然后将其提交到你的雇主拥有的任何变更控制过程中。在我的世界里浪费了很多时间。
相反,您可以
string LogFilePath = "\\LogFilePath";
string strExcelDataOutPut = "\\FolderPath";
string sPath = "\filePath";
变成类似
的东西 string LogFilePath = Dts.Variables["LogPath"].Value.ToString();
string strExcelDataOutPut = Dts.Variables["ExcelPath"].Value.ToString();
string sPath = Dts.Variables["FilePath"].Value.ToString();
那是什么让你?现在您 运行 您的脚本基于 SSIS 中的变量。您可以通过配置或参数化(取决于部署模型)对这些变量进行更改,然后您的包行为会发生变化而无需更改代码。您正在更新某个存储库中的外部值而不是代码本身。在我工作的环境中,与代码更改相比,实施更改通常风险要低得多(即使您所做的只是更改变量的值)。
除非您已经构建了一个进程来在那里使用您的自定义日志记录,否则请停止并使用 native tooling。引发信息、警告或错误消息。否则,您将需要确保 SSIS 可以写入该位置(稍后会详细介绍)。
Dts.Events.FireError(0, "Excel Writer", "Error Occurred...Please see the error Message :" + ex.Message, String.Empty, 0);
现在当您的包是 运行 时,该信息将转储到错误处理程序。如果您使用项目部署模型,该信息将自动记录到 SSISDB.catalog.operation_messages table 并显示在您的友好报告中。否则,转到 configure logging,SSIS 会将这些事件写入 table、平面文件、事件查看器、分析器 and/or 和 XML 文件。重要的是除非你有充分的理由,否则不要重新发明轮子。
当您使用 运行 此 SSIS 程序包时,您需要确保使用相对于 32 位或 64 位版本的 Office 而言正确的 dtexec 版本。这咬了很多人的屁股。 Office一般默认32位安装,有点可惜
当这个包运行时,即它在SQL服务器上运行,可能是SQL代理作业的一部分,运行 SQL 代理的帐户可能需要通常授予该帐户的更高级别的权限。它需要网络访问该文件共享到的任何地方。它将需要 InteractWithDesktop to be able to instantiate an instance of Excel and then do the needful. The SQL Agent job step will need to ensure that it has correctly flagged the SSIS package to be run as 32 bit 而不是 64(默认值)。如果您没有实现日志记录并且您没有使用项目部署模型,那么包会生成错误,错误消息将在 SQL 代理作业历史记录中捕获。这在某些时候会有用。
所以我遇到了这个 Microsoft Blog。虽然这很奇怪为什么你需要创建桌面文件夹但它有效。如果 link 被删除,请参阅下面的答案
分辨率 ************ ·
C:\Windows\SysWOW64\config\ 中的“systemprofile”文件夹中似乎需要“桌面”文件夹才能打开 Excel 文件·
在位置 C:\Windows\SysWOW64\config\systemprofile 下为 Windows 2008 Server (x64) 创建“桌面”文件夹 ·
对于 32 位 Windows 2008 服务器,在位置 C:\Windows\System32\config\systemprofile ·
下创建“桌面”文件夹创建文件夹后,SQL 服务器作业应该成功执行