C# Error: Microsoft Excel cannot access the file '...'. There are several possible reasons
C# Error: Microsoft Excel cannot access the file '...'. There are several possible reasons
我开发了一个 ASP.Net MVC 应用程序,即在 IIS 服务器上 运行。我写了一个代码来读取 CSV 并将它的行插入到数据库中。
[HttpPost]
public ActionResult InsertPosition(int id, HttpPostedFileBase position)
{
var posicoesExistentes = db.tbPositions.Where(s => s.id_unique == id).AsEnumerable();
foreach (tbPosition posicao in posicoesExistentes)
{
db.tbPositions.Remove(posicao);
}
if (!Directory.Exists(Server.MapPath("~/App_Data/")))
{
System.IO.Directory.CreateDirectory(Server.MapPath("~/App_Data/"));
}
string excelPath = Server.MapPath("~/App_Data/" + position.FileName);
if (System.IO.File.Exists(excelPath))
{
System.IO.File.Delete(excelPath);
}
position.SaveAs(excelPath);
string tempPath = Server.MapPath("~/App_Data/" + "tmp_" + position.FileName);
System.IO.File.Copy(excelPath, tempPath, true);
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(tempPath, ReadOnly: true,Editable:false);
Excel.Worksheet worksheet = workbook.ActiveSheet;
Excel.Range range = worksheet.UsedRange;
application.Visible = true;
for (int row = 1; row < range.Rows.Count - 1; row++)
{
tbPosition p = new tbPosition();
p.position = (((Excel.Range)range.Cells[row, 1]).Text == "") ? null : Convert.ToInt32(((Excel.Range)range.Cells[row, 1]).Text);
p.left = ((Excel.Range)range.Cells[row, 2]).Text;
p.right = ((Excel.Range)range.Cells[row, 3]).Text;
p.paper = ((Excel.Range)range.Cells[row, 4]).Text;
p.denomination = ((Excel.Range)range.Cells[row, 5]).Text;
p.material = ((Excel.Range)range.Cells[row, 6]).Text;
p.norme = ((Excel.Range)range.Cells[row, 7]).Text;
p.finalized_measures = ((Excel.Range)range.Cells[row, 8]).Text;
p.observation = ((Excel.Range)range.Cells[row, 9]).Text;
p.id_unique = id;
db.tbPositions.Add(p);
db.SaveChanges();
}
workbook.Close(true, Type.Missing, Type.Missing);
application.Quit();
System.IO.File.Delete(tempPath);
return Json("Success", JsonRequestBehavior.AllowGet);
}
但在 return 中我收到错误消息“Microsoft Excel 无法访问文件“...”。当我尝试打开请求的 excel 文件时,可能有多种原因。
我已经尝试以只读方式打开文件,我已经尝试授予对指定文件夹的权限,多种关闭 excel 文件的方法,并创建原始文件的副本并阅读他。但是这些解决方案中的每一个都不成功。我在这里错过了什么?
不支持
简短的回答是,在 UI 上下文之外不支持尝试使用自动化 API 以编程方式操作 Excel 文档。您 将 遇到各种挫折(例如,允许 API 显示对话框 - 如果 "OK" 是 运行 在网络服务器上?)。
微软明确地state this here
Microsoft does not recommend or support server-side Automation of Office.
那我用什么?
我建议使用 OpenXML SDK - 这是免费的,完全支持并且比自动化 API 快得多。
Aspose也有一套产品,不过不是免费的,我没用过
但我必须这样做
但是,如果您绝对必须使用 COM API,那么以下内容可能会对您有所帮助:
这里有龙
Excel 中自动化的最大问题是您需要确保在使用它们时关闭每个引用(通过对其调用 ReleaseComObject)。
例如,以下代码将导致 Excel 保持打开状态:
var range;
range = excelApplication.Range("A1");
range = excelApplication.Range("A2");
System.Runtime.InteropServices.Marshal.ReleaseComObject(range)
range = Nothing
这是因为在获取范围 "A1" 的调用中还遗留了一个引用。
因此,我建议围绕 Excel class 编写一个包装器,以便任何访问,例如,一个范围在访问新范围之前释放任何先前访问的范围。
作为参考,这里是我在 class 中用来释放 COM 对象的代码 我写的:
Private Sub ReleaseComObject(ByVal o As Object)
Try
If Not IsNothing(o) Then
While System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0
'Wait for COM object to be released.'
End While
End If
o = Nothing
Catch exc As System.Runtime.InteropServices.COMException
LogError(exc) ' Suppress errors thrown here '
End Try
End Sub
试试这个
protected void ImportCSV(object sender, EventArgs e)
{
importbtn();
}
public class Item
{
public Item(string line)
{
var split = line.Split(',');
string FIELD1 = split[0];
string FIELD2 = split[1];
string FIELD3 = split[2];
string mainconn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(mainconn))
{
using (SqlCommand cmd = new SqlCommand("storedProcedureName", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@FIELD1", SqlDbType.VarChar).Value = FIELD1;
cmd.Parameters.AddWithValue("@FIELD2", SqlDbType.VarChar).Value = FIELD2;
cmd.Parameters.AddWithValue("@FIELD3", SqlDbType.VarChar).Value = FIELD3;
con.Open();
cmd.ExecuteNonQuery();
}
}
}
}
private void importbtn()
{
try
{
string csvPath = Server.MapPath("~/Files/") + Path.GetFileName(FileUpload1.PostedFile.FileName);
FileUpload1.SaveAs(csvPath);
var listOfObjects = File.ReadLines(csvPath).Select(line => new Item(line)).ToList();
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[3] { new DataColumn("FIELD1", typeof(string)),
new DataColumn("FIELD2", typeof(string)),
new DataColumn("FIELD3",typeof(string)) });
string csvData = File.ReadAllText(csvPath);
foreach (string row in csvData.Split('\n'))
{
if (!string.IsNullOrEmpty(row))
{
dt.Rows.Add();
int i = 0;
//Execute a loop over the columns.
foreach (string cell in row.Split(','))
{
dt.Rows[dt.Rows.Count - 1][i] = cell;
i++;
}
}
}
GridView1.DataSource = dt;
GridView1.DataBind();
Label1.Text = "File Attached Successfully";
}
catch (Exception ex)
{
Message.Text = "Please Attach any File" /*+ ex.Message*/;
}
}
我开发了一个 ASP.Net MVC 应用程序,即在 IIS 服务器上 运行。我写了一个代码来读取 CSV 并将它的行插入到数据库中。
[HttpPost]
public ActionResult InsertPosition(int id, HttpPostedFileBase position)
{
var posicoesExistentes = db.tbPositions.Where(s => s.id_unique == id).AsEnumerable();
foreach (tbPosition posicao in posicoesExistentes)
{
db.tbPositions.Remove(posicao);
}
if (!Directory.Exists(Server.MapPath("~/App_Data/")))
{
System.IO.Directory.CreateDirectory(Server.MapPath("~/App_Data/"));
}
string excelPath = Server.MapPath("~/App_Data/" + position.FileName);
if (System.IO.File.Exists(excelPath))
{
System.IO.File.Delete(excelPath);
}
position.SaveAs(excelPath);
string tempPath = Server.MapPath("~/App_Data/" + "tmp_" + position.FileName);
System.IO.File.Copy(excelPath, tempPath, true);
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(tempPath, ReadOnly: true,Editable:false);
Excel.Worksheet worksheet = workbook.ActiveSheet;
Excel.Range range = worksheet.UsedRange;
application.Visible = true;
for (int row = 1; row < range.Rows.Count - 1; row++)
{
tbPosition p = new tbPosition();
p.position = (((Excel.Range)range.Cells[row, 1]).Text == "") ? null : Convert.ToInt32(((Excel.Range)range.Cells[row, 1]).Text);
p.left = ((Excel.Range)range.Cells[row, 2]).Text;
p.right = ((Excel.Range)range.Cells[row, 3]).Text;
p.paper = ((Excel.Range)range.Cells[row, 4]).Text;
p.denomination = ((Excel.Range)range.Cells[row, 5]).Text;
p.material = ((Excel.Range)range.Cells[row, 6]).Text;
p.norme = ((Excel.Range)range.Cells[row, 7]).Text;
p.finalized_measures = ((Excel.Range)range.Cells[row, 8]).Text;
p.observation = ((Excel.Range)range.Cells[row, 9]).Text;
p.id_unique = id;
db.tbPositions.Add(p);
db.SaveChanges();
}
workbook.Close(true, Type.Missing, Type.Missing);
application.Quit();
System.IO.File.Delete(tempPath);
return Json("Success", JsonRequestBehavior.AllowGet);
}
但在 return 中我收到错误消息“Microsoft Excel 无法访问文件“...”。当我尝试打开请求的 excel 文件时,可能有多种原因。
我已经尝试以只读方式打开文件,我已经尝试授予对指定文件夹的权限,多种关闭 excel 文件的方法,并创建原始文件的副本并阅读他。但是这些解决方案中的每一个都不成功。我在这里错过了什么?
不支持
简短的回答是,在 UI 上下文之外不支持尝试使用自动化 API 以编程方式操作 Excel 文档。您 将 遇到各种挫折(例如,允许 API 显示对话框 - 如果 "OK" 是 运行 在网络服务器上?)。
微软明确地state this here
Microsoft does not recommend or support server-side Automation of Office.
那我用什么?
我建议使用 OpenXML SDK - 这是免费的,完全支持并且比自动化 API 快得多。
Aspose也有一套产品,不过不是免费的,我没用过
但我必须这样做
但是,如果您绝对必须使用 COM API,那么以下内容可能会对您有所帮助:
这里有龙
Excel 中自动化的最大问题是您需要确保在使用它们时关闭每个引用(通过对其调用 ReleaseComObject)。
例如,以下代码将导致 Excel 保持打开状态:
var range;
range = excelApplication.Range("A1");
range = excelApplication.Range("A2");
System.Runtime.InteropServices.Marshal.ReleaseComObject(range)
range = Nothing
这是因为在获取范围 "A1" 的调用中还遗留了一个引用。
因此,我建议围绕 Excel class 编写一个包装器,以便任何访问,例如,一个范围在访问新范围之前释放任何先前访问的范围。
作为参考,这里是我在 class 中用来释放 COM 对象的代码 我写的:
Private Sub ReleaseComObject(ByVal o As Object)
Try
If Not IsNothing(o) Then
While System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0
'Wait for COM object to be released.'
End While
End If
o = Nothing
Catch exc As System.Runtime.InteropServices.COMException
LogError(exc) ' Suppress errors thrown here '
End Try
End Sub
试试这个
protected void ImportCSV(object sender, EventArgs e)
{
importbtn();
}
public class Item
{
public Item(string line)
{
var split = line.Split(',');
string FIELD1 = split[0];
string FIELD2 = split[1];
string FIELD3 = split[2];
string mainconn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(mainconn))
{
using (SqlCommand cmd = new SqlCommand("storedProcedureName", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@FIELD1", SqlDbType.VarChar).Value = FIELD1;
cmd.Parameters.AddWithValue("@FIELD2", SqlDbType.VarChar).Value = FIELD2;
cmd.Parameters.AddWithValue("@FIELD3", SqlDbType.VarChar).Value = FIELD3;
con.Open();
cmd.ExecuteNonQuery();
}
}
}
}
private void importbtn()
{
try
{
string csvPath = Server.MapPath("~/Files/") + Path.GetFileName(FileUpload1.PostedFile.FileName);
FileUpload1.SaveAs(csvPath);
var listOfObjects = File.ReadLines(csvPath).Select(line => new Item(line)).ToList();
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[3] { new DataColumn("FIELD1", typeof(string)),
new DataColumn("FIELD2", typeof(string)),
new DataColumn("FIELD3",typeof(string)) });
string csvData = File.ReadAllText(csvPath);
foreach (string row in csvData.Split('\n'))
{
if (!string.IsNullOrEmpty(row))
{
dt.Rows.Add();
int i = 0;
//Execute a loop over the columns.
foreach (string cell in row.Split(','))
{
dt.Rows[dt.Rows.Count - 1][i] = cell;
i++;
}
}
}
GridView1.DataSource = dt;
GridView1.DataBind();
Label1.Text = "File Attached Successfully";
}
catch (Exception ex)
{
Message.Text = "Please Attach any File" /*+ ex.Message*/;
}
}