当我使用EPPlus库从模板生成Excel文件时,我遇到了一些问题。该文件包含第一个电子表格,其中包含用于在以下表格中填充数据透视表的数据。
当我打开生成的文件时,收到以下错误消息: “Excel在'sampleFromTemplate.xlsx'中找到了不可读的内容。是否要恢复此工作簿的内容?我相信此工作簿的来源,请单击是。”
我显然单击是,然后获取对文件进行的修复的摘要,以及指向包含此内容的xml格式化日志文件的链接:
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<logFileName>error095080_01.xml</logFileName>
<summary>Errors were detected in file 'C:\TEMP\sampleFromTemplate.xlsx'</summary>
<repairedRecords summary="Following is a list of repairs:">
<repairedRecord>Repaired Records: Table from /xl/tables/table1.xml part (Table)</repairedRecord>
</repairedRecords>
</recoveryLog>
这显然是由我在代码中定义的命名范围(“Table1”)引起的,用于指示要用于数据透视表的数据。模板中已经有一个名为“Table1”的“表名”,但我似乎无法通过ExcelPackage.Worksheet.Names集合访问它。作为EPPlus的新手,并没有非常熟悉Excel,我不明白我做错了什么。这是我生成文件的代码:
private string GenerateFromTemplate(string fileName, string templateName, DataTable tab)
{
FileInfo newFile = new FileInfo(string.Format("C:\\MyPath\\{0}.xlsx", fileName));
FileInfo templateFile = new FileInfo(string.Format("C:\\MyPath\\{0}.xlsx", templateName));
try
{
using (ExcelPackage pkg = new ExcelPackage(newFile, templateFile))
{
ExcelWorksheet sheet = pkg.Workbook.Worksheets["MyDataSheet"];
ExcelRange range = sheet.Cells[string.Format("A1:U{0}", dt.Rows.Count)];
pkg.Workbook.Names.Add("Table1", range as ExcelRangeBase);
int sheetRowIndex = 2;
foreach (DataRow row in this.dt.Rows)
{
sheet.Cells[sheetRowIndex, 1].Value = row["Row1"];
sheet.Cells[sheetRowIndex, 2].Value = row["Row2"];
[...]
sheet.Cells[sheetRowIndex, 21].Value = row["Row21"];
sheetRowIndex++;
}
pkg.Save();
return newFile.FullName;
}
}
catch (IOException ex) { return ex.Message; }
}
请注意,无论如何都会正确填充数据透视表,为什么会发生这种情况呢?
谢谢: - )
答案 0 :(得分:28)
我自己遇到了这个问题并修复了它,如果其他人碰到了我的解决方案:
这是使用asp.net,原因显而易见,它不适用。
我的问题不在于表格范围,Epplus生成的文件很好,而是服务器响应将页面响应附加到excel文件,显然使文件无效。在发送文件后立即结束服务器响应修复了我的问题,其中包括以下内容:
Response.BinaryWrite(pck.GetAsByteArray()); // send the file
Response.End();
答案 1 :(得分:8)
问题没有解决,但现在我知道原因。这个“Table1”的东西不是命名范围而是一个表,我可以通过工作表的“Tables”集合访问它。
现在,问题是EPPlus中的Tables集合和Table对象都是只读的,所以我不能从我的代码中定义表的维度,也不能删除它或添加新的以满足我的需要。 EPPlus的作者已经提到它可能有一天会被实现(here和here)总线,因为消息已经快3年了,我想没有希望看到这种情况发生......
无论如何,我希望这会帮助任何人遇到同样的问题。
[编辑]我终于想出了一种绕过问题的方法:ExcelTable对象有一个名为“TableXml”的可写属性,它包含表的xml定义 - 当然 - 它的范围。以下是我的案例内容:
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<table dataCellStyle="Normal 2" headerRowCellStyle="Normal 2" headerRowDxfId="70" totalsRowShown="0" insertRow="1" ref="A1:U2" displayName="Table1" name="Table1" id="1" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<autoFilter ref="A1:U2"/>
<tableColumns count="21">
<tableColumn dataCellStyle="Normal 2" name="Activity" id="1"/>
<tableColumn dataCellStyle="Normal 2" name="Category" id="21"/>
[...]
<tableColumn dataCellStyle="Normal 2" name="Closed Year" id="20" dataDxfId="62"/>
</tableColumns>
<tableStyleInfo name="TableStyleMedium9" showColumnStripes="0" showRowStripes="1" showLastColumn="0" showFirstColumn="0"/>
</table>
我们感兴趣的是“table”和“autoFilter”节点中的“ref”属性,因为更改它们的值允许重新定义表格的范围。
我继续这样做:
XmlDocument tabXml = sheet.Tables(0).TableXml;
XmlNode tableNode = tabXml.ChildNodes[1];
tableNode.Attributes["ref"].Value = string.Format("A1:U{0}", dt.Rows.Count + 1);
XmlNode autoFilterNode = tableNode.ChildNodes[0];
autoFilterNode.Attributes["ref"].Value = string.Format("A1:U{0}", dt.Rows.Count + 1);
现在我的Excel文件正确生成,“Table1”符合我的数据的实际范围!
答案 2 :(得分:5)
我花了大约4个小时来解决这个问题,作为我的问题&amp;解决方案不在帖子中,我是为任何未来的访问者写的,
我的问题是由excel表中的重复列引起的。向一列添加空格后,问题就解决了。 有趣的是,当我通过MS excel生成数据透视表时,错误永远不会出现,只有当我使用epplus在excel文件中生成数据透视表时才出现。让bug更难找到
答案 3 :(得分:3)
当我遇到一个在每行后添加额外列分隔符的错误时,我遇到了这个问题:
head1{tab}head2{tab}
col11{tab}col21{tab}
col22{tab}col22{tab}
最后一列之后的额外标签以同样的方式破坏了生成的Excel电子表格,并删除它修复了问题。注意我正在使用LoadFromText
从文本数据中一次加载整个工作表。这可能不是OP的问题,但未来的搜索者可能会发现这有用。
答案 4 :(得分:2)
在编辑工作簿时遇到此问题时,在其标题中使用具有特殊格式的表(Windings字体用于显示特殊符号)。不得不删除格式以修复邮件。
答案 5 :(得分:0)
不同的设置(返回流),但同样的问题(损坏的表记录)。就我而言,问题是对ExcelPackage.Save()的显式调用:
using (var excelPackage = new ExcelPackage())
{
/* ... removed code for clarity */
// caused the stream to contain the file 2 times,
// save is already called by GetAsByteArray()
//excelPackage.Save();
return new MemoryStream(excelPackage.GetAsByteArray());
}
答案 6 :(得分:0)
当我使用C#和epplus从表中删除所有行时,我的问题解决了。