代码之家  ›  专栏  ›  技术社区  ›  tigrou

在epplus中枚举范围时,是否始终按以下顺序检索单元格:按行排序,然后按列排序?

  •  0
  • tigrou  · 技术社区  · 6 年前

    假设我有以下代码:

    using (ExcelPackage package = new ExcelPackage(...))
    {
       foreach(var cell in package.Workbook.Worksheets[1].Cells["A1:E5"])
       {
           //do something with "cell"
       }
    }
    

    以及以下Excel工作表:

       A      B      C      D      E
    1  foo    bar    .      .      .
    2  .      .      .      .      .
    3  .      .      hello  .      .      
    4  .      .      world  .      .
    5  .      .      .      .      .
    

    检索元素的顺序是否始终为:

    foo => bar => hello => world ?
    

    从我目前所做的努力来看,这似乎总是正确的。 但这并不意味着总是这样。

    在.xlsx文件中,excel似乎也按此顺序序列化单元格,即使这些单元格已按不同的顺序编辑。

    excelworksheet类中的文档并没有说明太多:

    //
    // Summary:
    //     Provides access to a range of cells
    public ExcelRange Cells { get; }
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   tigrou    6 年前

    我回答自己的问题。

    tltr:在当前的epplus版本(v4.5.1)中,给定范围的单元格总是按以下顺序枚举:按行排序,然后按列排序。


    我是通过查看epplus发现的 implementation .

    给定工作表的单元格存储在 RangeCollection 对象:

    class ExcelWorksheet
    {
        RangeCollection _cells;
    }
    

    范围集合 包含单元格列表。这个列表总是按 RangeID . rangeid是行/列/工作表索引的组合。 这允许epplus通过执行二进制搜索来快速查找单元格的索引(对于给定的行和列)。

    class RangeCollection
    {
        List<IRangeID> _cells;
    
        int IndexOf(ulong rangeID)
        {
            return Array.BinarySearch(...);
        }
    }
    
    class ExcelCell : IRangeID
    {
        ulong RangeID
        {
            get
            {
                return GetCellID(_worksheet.SheetID, Row, Column);
            }
        }
    
        ulong GetCellID(int SheetID, int row, int col)
        {
            return ((ulong)SheetID) + (((ulong)col) << 15) + (((ulong)row) << 29);
        }
    }
    

    枚举给定范围的单元格时,epplus将使用该排序列表枚举该范围内的单元格:

    class ExcelRange 
    {
        public bool MoveNext()
        {
            _index++;
            //...
            if (...) 
            {
               GetStartIndexEnum(_fromRow, _fromCol, _toRow, _toCol);
               //...
               GetNextIndexEnum(_fromRow, _fromCol, _toRow, _toCol);
            }
        }
    
        object IEnumerator.Current
        {
            get
            {
                return /*...*/ _worksheet._cells[_index] as ExcelCell /*...*/
            }
        }
    }
    

    GetStartIndexEnum() GetNextIndexEnum() 用于快速跳过当前枚举范围之外的单元格。单元格的检查和枚举顺序与始终排序的rangecollection本身相同。