如何插入Excel单元而不创建损坏的文件?
问题描述:
我正在使用OpenXML SDK来更新Excel电子表格的内容。将单元格插入Excel行时,必须按正确的顺序插入,否则文件将无法在Excel中正确打开。我正在使用以下代码来查找将插入单元格后的第一个单元格。此代码来几乎直接从OpenXML SDK documentation如何插入Excel单元而不创建损坏的文件?
public static Cell GetFirstFollowingCell(Row row, string newCellReference)
{
Cell refCell = null;
foreach (Cell cell in row.Elements<Cell>())
{
if (string.Compare(cell.CellReference.Value, newCellReference, true) > 0)
{
refCell = cell;
break;
}
}
return refCell;
}
当我编辑与此代码文件,然后在Excel中打开它们,Excel报表,该文件已损坏。 Excel能够修复文件,但大部分数据都从工作簿中删除。为什么这会导致文件损坏?
备注:在转向痛苦的低级别OpenXML SDK之前,我尝试了两个不同的.NET Excel库。 NPOI创建了包含损坏的电子表格,并且每当我尝试保存时,EPPlus都会抛出异常。我正在使用每个版本的最新版本。
答
您使用的代码严重瑕疵。这非常不幸,因为它来自文档。对于仅使用前26列的电子表格,它可能是可以接受的,但在遇到“更宽”的电子表格时会失败。前26列按字母顺序排列,A-Z。第27-52列被命名为AA-AZ。列53-78被命名为BA-BZ。 (你应该注意到的模式。)
细胞“AA1”应该来后所有细胞与单个字符列名(即“A1” - “Z1”)。我们来看看比较单元格“AA1”和单元格“B1”的当前代码。
-
string.Compare("B1", "AA1", true)
返回值1 - 的代码解释此意味着 “AA1” 应放置之前细胞 “B1”。
- 呼叫代码将在XML中的“B1”之前插入“AA1”。
此时单元格将出现故障,Excel文件已损坏。显然,string.Compare
本身并不足以确定连续的单元格的正确顺序。需要更复杂的比较。
public static bool IsNewCellAfterCurrentCell(string currentCellReference, string newCellReference)
{
var columnNameRegex = new Regex("[A-Za-z]+");
var currentCellColumn = columnNameRegex.Match(currentCellReference).Value;
var newCellColumn = columnNameRegex.Match(newCellReference).Value;
var currentCellColumnLength = currentCellColumn.Length;
var newCellColumnLength = newCellColumn.Length;
if (currentCellColumnLength == newCellColumnLength)
{
var comparisonValue = string.Compare(currentCellColumn, newCellColumn, StringComparison.OrdinalIgnoreCase);
return comparisonValue > 0;
}
return currentCellColumnLength < newCellColumnLength;
}
如果你想把它放到一个新的单元格列“BC”和你比较,细胞“D5”你会使用IsCellAfterColumn("D5", "BC5")
。将新的比较函数代入原始代码并用LINQ简化:
public static Cell GetFirstFollowingCell(Row row, string newCellReference)
{
var rowCells = row.Elements<Cell>();
return rowCells.FirstOrDefault(c => IsNewCellAfterCurrentCell(c.CellReference.Value, newCellReference));
}