简体   繁体   English

如何在不创建损坏文件的情况下插入Excel单元格?

[英]How do I insert Excel cells without creating a corrupt file?

I'm using the OpenXML SDK to update the contents of an Excel spreadsheet. 我正在使用OpenXML SDK更新Excel电子表格的内容。 When inserting cells into an Excel row they must be inserted in the correct order or the file will not open properly in Excel. 将单元格插入Excel行时,必须按正确的顺序插入它们,否则文件将无法在Excel中正确打开。 I'm using the following code to find the first cell that will be after the cell I am inserting. 我正在使用以下代码查找要插入的单元格之后的第一个单元格。 This code comes almost directly from the OpenXML SDK documentation 这段代码几乎直接来自OpenXML SDK文档

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;
}

When I edit files with this code and then open them in Excel, Excel reports that the file is corrupted. 当我使用此代码编辑文件,然后在Excel中打开文件时,Excel报告文件已损坏。 Excel is able to repair the file, but most of the data is removed from the workbook. Excel能够修复该文件,但是大多数数据已从工作簿中删除。 Why does this result in file corruption? 为什么这会导致文件损坏?

Side note: I tried two different .NET Excel libraries before turning to the painfully low-level OpenXML SDK. 旁注:在尝试使用痛苦的低级OpenXML SDK之前,我尝试了两种不同的.NET Excel库。 NPOI created spreadsheets with corruption and EPPlus threw an exception whenever I tried to save. NPOI创建的电子表格存在损坏,每当我尝试保存时,EPPlus都会引发异常。 I was using the most recent version of each. 我正在使用每个的最新版本。

The code you are using is seriously flawed. 您使用的代码存在严重缺陷。 This is very unfortunate, seeing as it comes from the documentation. 看到它来自文档,这是非常不幸的。 It may work acceptably for spreadsheets that only use the first 26 columns but will fail miserably when confronted with "wider" spreadsheets. 对于仅使用前26列的电子表格来说,它可能可以接受,但是当遇到“更宽”的电子表格时,它会惨败。 The first 26 columns are named alphabetically, AZ. 前26列按字母顺序命名为AZ。 Columns 27-52 are named AA-AZ. 第27-52列称为AA-AZ。 Column 53-78 are named BA-BZ. 列53-78命名为BA-BZ。 (You should notice the pattern.) (您应该注意该模式。)

Cell "AA1" should come after all cells with a single character column name (ie "A1" - "Z1"). 单元格“ AA1”应排所有具有单个字符列名称(即“ A1”-“ Z1”)的单元格之后。 Let's examine the current code comparing cell "AA1" with cell "B1". 让我们检查一下当前代码,将单元格“ AA1”与单元格“ B1”进行比较。

  1. string.Compare("B1", "AA1", true) returns the value 1 string.Compare("B1", "AA1", true)返回值1
  2. The code interprets this to mean that "AA1" should be placed before cell "B1". 代码将其解释为意味着应将“ AA1”放在单元格“ B1” 之前
  3. The calling code will insert "AA1" before "B1" in the XML. 调用代码将在XML中的“ B1” 之前插入“ AA1”。

At this point the cells will be out of order and the Excel file is corrupted. 此时,单元格将出现故障,Excel文件已损坏。 Clearly, string.Compare by itself is not a sufficient test to determine the proper order of cells in a row. 显然, string.Compare本身不足以确定行中单元格的正确顺序。 A more sophisticated comparison is required. 需要更复杂的比较。

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;
}

If you wanted to place a new cell in column "BC" and you were comparing to cell "D5" you would use IsCellAfterColumn("D5", "BC5") . 如果要在“ BC”列中放置一个新单元格,并且要与“ D5”单元格进行比较,则可以使用IsCellAfterColumn("D5", "BC5") Substituting the new comparison function into the original code and simplifying with LINQ: 将新的比较功能替换为原始代码,并使用LINQ进行简化:

public static Cell GetFirstFollowingCell(Row row, string newCellReference)
{
    var rowCells = row.Elements<Cell>();
    return rowCells.FirstOrDefault(c => IsNewCellAfterCurrentCell(c.CellReference.Value, newCellReference));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用C#打印没有隐藏单元格的Excel? - How do I print Excel without hidden cells with C#? 如何写入Excel中的特定单元格? - How do I write to specific cells in Excel? 如何使用git存储库替换损坏的文件? - How do I replace a corrupt file using a git repository? 我在Gridview中显示Excel文件的内容。 如何处理合并的单元格? - I am displaying the contents of an Excel file in a Gridview. How do I handle merged cells? 如何在没有收到警告的情况下存储Excel文件 - How do I store Excel File without getting the warning 如何在不创建外部对象的情况下加载xaml文件? - How do I load a xaml file without creating the outer object? 在C#中解析Excel文件,单元格似乎被切断为255个字符...我该如何阻止它? - Parsing an Excel file in C#, the cells seem to get cut off at 255 characters… how do I stop that? itextsharp创建损坏的/空白pdf文件,i-9文件 - itextsharp creating a corrupt / blank pdf file, i-9 file 使用SQL(ADO)将Excel拉入C#时,如何排除空行而不排除空单元格? - How do I exclude null rows without excluding null cells when pulling Excel into C# using SQL (ADO)? 如何自动格式化包含字符串和数字的 Excel 单元格? - How do I autoformat excel cells that contains both strings and numbers?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM