- [Bug] Fix Column more than 255 rows cannot be read error [#208](https://github.com/shps951023/MiniExcel/issues/#208)
This commit is contained in:
wei 2021-04-20 09:57:15 +08:00
parent 7c2a4dd337
commit 9b593cb474
14 changed files with 213 additions and 55 deletions

View File

@ -25,14 +25,16 @@ At present, most popular frameworks need to load all the data into the memory to
### Get Started
- [Excel Query](#getstart1)
- [Create Excel](#getstart2)
- [Fill Data To Excel Template](#getstart3)
- [Excel Column Name/Index/Ignore Attribute](#getstart4)
- [Examples](#getstart5)
### Demo
- LINQPad : Download [Basic Demo.linq](drafts/【MiniExcel】Basic%20Demo.linq)
### Installation

View File

@ -39,9 +39,6 @@ MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工
### Demo
- LINQPad : Download [Basic Demo.linq](drafts/[MiniExcel]Basic%20Demo.linq)
### 安装
请查看 [from NuGet](https://www.nuget.org/packages/MiniExcel)

View File

@ -1,4 +1,4 @@
[![NuGet](https://img.shields.io/nuget/v/MiniExcel.svg)](https://www.nuget.org/packages/MiniExcel) [![](https://img.shields.io/nuget/dt/MiniExcel.svg)](https://www.nuget.org/packages/MiniExcel) [![Build status](https://ci.appveyor.com/api/projects/status/b2vustrwsuqx45f4/branch/master?svg=true)](https://ci.appveyor.com/project/shps951023/miniexcel/branch/master) [![.NET Framework](https://img.shields.io/badge/.NET%20Framework-%3E%3D%204.5-red.svg)](#) [![.NET Standard](https://img.shields.io/badge/.NET%20Standard-%3E%3D%202.0-red.svg)](#) [![.NET](https://img.shields.io/badge/.NET%20-%3E%3D%205.0-red.svg)](#)
[![NuGet](https://img.shields.io/nuget/v/MiniExcel.svg)](https://www.nuget.org/packages/MiniExcel) [![](https://img.shields.io/nuget/dt/MiniExcel.svg)](https://www.nuget.org/packages/MiniExcel) [![Build status](https://ci.appveyor.com/api/projects/status/b2vustrwsuqx45f4/branch/master?svg=true)](https://ci.appveyor.com/project/shps951023/miniexcel/branch/master) [![.NET Framework](https://img.shields.io/badge/.NET%20Framework-%3E%3D%204.5-red.svg)](#) [![.NET Standard](https://img.shields.io/badge/.NET%20Standard-%3E%3D%202.0-red.svg)](#) [![.NET](https://img.shields.io/badge/.NET%20-%3E%3D%205.0-red.svg)](#) [![](https://img.shields.io/badge/Facebook-1877F2?logo=facebook&logoColor=white)](https://www.facebook.com/MiniExcel)
---
@ -6,10 +6,6 @@
---
Facebook : https://www.facebook.com/miniexcel
---
### 簡介
MiniExcel 簡單、高效避免OOM的.NET處理Excel查、寫、填充工具。
@ -39,10 +35,6 @@ MiniExcel 簡單、高效避免OOM的.NET處理Excel查、寫、填充工具。
- [範例](#getstart5)
### Demo
- LINQPad : Download [Basic Demo.linq](drafts/[MiniExcel]Basic%20Demo.linq)
### 安裝
請查看 [from NuGet](https://www.nuget.org/packages/MiniExcel)

View File

@ -6,6 +6,9 @@
---
### 0.13.2
- [Bug] Fix Column more than 255 rows cannot be read error [#208](https://github.com/shps951023/MiniExcel/issues/#208)
### 0.13.1
- [New] SaveAsByTemplate by template bytes, convenient to cache and support multiple users to read the same template at the same time #189
- [New] SaveAsByTemplate support input `IEnmerable<IDicionary<string,object>> or DapperRows or DataTable` parameters [#201](https://github.com/shps951023/MiniExcel/issues/201)

View File

@ -7,6 +7,9 @@
---
### 0.13.2
- [Bug] 列超过 255 行无法读取错误 [#208](https://github.com/shps951023/MiniExcel/issues/#208)
### 0.13.1
- [New] SaveAsByTemplate 支持读取模板 byte[],方便缓存跟支持多用户同时读取同一个模板 #189
- [New] SaveAsByTemplate 支持传入 `IEnmerable<IDicionary<string,object>> 或 DapperRows 或 DataTable` 参数 [#201](https://github.com/shps951023/MiniExcel/issues/201)

View File

@ -7,6 +7,9 @@
---
### 0.13.2
- [Bug] 列超過 255 行無法讀取錯誤 [#208](https://github.com/shps951023/MiniExcel/issues/#208)
### 0.13.1
- [New] SaveAsByTemplate 支持讀取模板 byte[],方便緩存跟支持多用戶同時讀取同一個模板 [#189](https://github.com/shps951023/MiniExcel/issues/189)
- [New] SaveAsByTemplate 支持傳入 `IEnmerable<IDicionary<string,object>> 或 DapperRows 或 DataTable` 參數 [#201](https://github.com/shps951023/MiniExcel/issues/201)

View File

@ -0,0 +1,87 @@
<Query Kind="Program">
<NuGetReference>Dapper</NuGetReference>
<NuGetReference>MiniExcel</NuGetReference>
<NuGetReference>Newtonsoft.Json</NuGetReference>
<NuGetReference>System.Data.SqlClient</NuGetReference>
<Namespace>Dapper</Namespace>
<Namespace>MiniExcelLibs</Namespace>
<Namespace>Newtonsoft.Json</Namespace>
<RemoveNamespace>System.Data</RemoveNamespace>
<RemoveNamespace>System.Diagnostics</RemoveNamespace>
<RemoveNamespace>System.Linq.Expressions</RemoveNamespace>
<RemoveNamespace>System.Text</RemoveNamespace>
<RemoveNamespace>System.Text.RegularExpressions</RemoveNamespace>
<RemoveNamespace>System.Threading</RemoveNamespace>
<RemoveNamespace>System.Transactions</RemoveNamespace>
<RemoveNamespace>System.Xml</RemoveNamespace>
<RemoveNamespace>System.Xml.Linq</RemoveNamespace>
<RemoveNamespace>System.Xml.XPath</RemoveNamespace>
</Query>
void Main()
{
Console.WriteLine(Helpers.GetAlphabetColumnName(255));
Console.WriteLine(Helpers.GetAlphabetColumnName(256));
Console.WriteLine(Helpers.GetAlphabetColumnName(257));
Console.WriteLine(Helpers.GetAlphabetColumnName(258));
Console.WriteLine(Helpers.GetAlphabetColumnName(16383));
//Console.WriteLine(Helpers.GetAlphabetColumnName(16384));
var _IntMappingAlphabet = Helpers._IntMappingAlphabet;
var _AlphabetMappingInt = Helpers._AlphabetMappingInt;
}
// You can define other methods, fields, classes and namespaces here
internal static class Helpers
{
private const int GENERAL_COLUMN_INDEX = 255;
private const int MAX_COLUMN_INDEX = 16383;
internal static Dictionary<int, string> _IntMappingAlphabet;
internal static Dictionary<string, int> _AlphabetMappingInt;
static Helpers()
{
if (_IntMappingAlphabet == null && _AlphabetMappingInt == null)
{
_IntMappingAlphabet = new Dictionary<int, string>();
_AlphabetMappingInt = new Dictionary<string, int>();
for (int i = 0; i <= GENERAL_COLUMN_INDEX; i++)
{
_IntMappingAlphabet.Add(i, IntToLetters(i));
_AlphabetMappingInt.Add(IntToLetters(i), i);
}
}
}
public static string GetAlphabetColumnName(int columnIndex)
{
if (columnIndex >= _IntMappingAlphabet.Count)
{
if (columnIndex > MAX_COLUMN_INDEX)
throw new InvalidDataException($"ColumnIndex {columnIndex} over excel vaild max index.");
for (int i = _IntMappingAlphabet.Count; i <= columnIndex; i++)
{
_IntMappingAlphabet.Add(i, IntToLetters(i));
_AlphabetMappingInt.Add(IntToLetters(i), i);
}
}
return _IntMappingAlphabet[columnIndex];
}
public static int GetColumnIndex(string columnName)
{
var columnIndex = _AlphabetMappingInt[columnName];
return columnIndex;
}
internal static string IntToLetters(int value)
{
value = value + 1;
string result = string.Empty;
while (--value >= 0)
{
result = (char)('A' + value % 26) + result;
value /= 26;
}
return result;
}
}

Binary file not shown.

View File

@ -1,24 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netstandard2.0;net5.0</TargetFrameworks>
<Version>0.13.1</Version>
<Version>0.13.2</Version>
</PropertyGroup>
<PropertyGroup>
<AssemblyName>MiniExcel</AssemblyName>
<Title>MiniExcel</Title>
<Product>MiniExcel</Product>
<PackageTags>excel;xlsx;micro-helper;mini;openxml;helper;</PackageTags>
<Description>
A high performance and easy Excel(xlsx,csv) Micro-Helper that avoids OOM and without third-party dependencies to create or dynamic/type POCO mapping query etc..
* Support excel template report generation with which you can easily export any data from your .NET classes to Excel.
<Description>A high performance and easy Excel(xlsx,csv) Micro-Helper that avoids OOM and without third-party dependencies to create or dynamic/type POCO mapping query etc..
* Support excel template report generation with which you can easily export any data from your .NET classes to Excel.
Github : https://github.com/shps951023/MiniExcel
China Gitee : https://gitee.com/dotnetchina/MiniExcel
Issues : github https://github.com/shps951023/MiniExcel/issues or China Gitee https://gitee.com/dotnetchina/MiniExcel/issues
Todo : https://github.com/shps951023/MiniExcel/projects/1?fullscreen=true
Facebook : https://www.facebook.com/miniexcel
China QQ : 813100564
</Description>
Github : https://github.com/shps951023/MiniExcel
Gitee : https://gitee.com/dotnetchina/MiniExcel
Issues : github https://github.com/shps951023/MiniExcel/issues or Gitee https://gitee.com/dotnetchina/MiniExcel/issues
Todo : https://github.com/shps951023/MiniExcel/projects/1?fullscreen=true
Facebook : https://www.facebook.com/miniexcel
QQ : 813100564
</Description>
<Authors>ITWeiHan</Authors>
<Copyright>©2021 WeiHan Lin</Copyright>
<license>https://raw.githubusercontent.com/shps951023/MiniExcel/master/LICENSE.md</license>
@ -26,11 +25,7 @@
<PackageProjectUrl>https://github.com/shps951023/MiniExcel</PackageProjectUrl>
<RepositoryUrl>https://github.com/shps951023/MiniExcel</RepositoryUrl>
<PackageIconUrl>https://user-images.githubusercontent.com/12729184/115023335-39440c80-9ef1-11eb-8771-7260d1e50d5a.png</PackageIconUrl>
<PackageReleaseNotes>
Please Check [Release Notes](https://github.com/shps951023/MiniExcel/tree/master/docs)
or
[China Gitee Release Notes](https://gitee.com/dotnetchina/MiniExcel/blob/master/docs/README.zh-CN.md)
</PackageReleaseNotes>
<PackageReleaseNotes>Please Check [Release Notes](https://github.com/shps951023/MiniExcel/tree/master/docs)</PackageReleaseNotes>
<RepositoryType>Github</RepositoryType>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461'">

View File

@ -44,7 +44,6 @@ namespace MiniExcelLibs.OpenXml
sheetZipEntry.Delete(); // ZipArchiveEntry can't update directly, so need to delete then create logic
var worksheet = doc.SelectSingleNode("/x:worksheet", _ns);
var sheetData = doc.SelectSingleNode("/x:worksheet/x:sheetData", _ns);
var newSheetData = sheetData.Clone(); //avoid delete lost data
@ -55,8 +54,11 @@ namespace MiniExcelLibs.OpenXml
//Update dimension && Check if the column contains a collection and get type and properties infomations
UpdateDimensionAndGetCollectionPropertiesInfos(inputMaps, ref doc, ref rows);
#region Render cell values
RenderRowsAndCells(stream, doc, sheetData);
}
private void RenderRowsAndCells(Stream stream, XmlDocument doc, XmlNode sheetData)
{
//Q.Why so complex?
//A.Because try to use string stream avoid OOM when rendering rows
sheetData.RemoveAll();
@ -219,7 +221,6 @@ namespace MiniExcelLibs.OpenXml
writer.Write($"</{prefix}sheetData>");
writer.Write(contents[1]);
}
#endregion
}
private static string CleanXml(string xml, string endPrefix)

View File

@ -61,7 +61,7 @@ namespace MiniExcelLibs.OpenXml
values.Add(p.Name, p.GetValue(value));
}
}
//TODO:DataTable & DapperRow
{
templateStream.CopyTo(stream);

View File

@ -4,24 +4,56 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
internal static partial class Helpers
{
private static Dictionary<int, string> _IntMappingAlphabet = new Dictionary<int, string>();
private static Dictionary<string, int> _AlphabetMappingInt = new Dictionary<string, int>();
private const int GENERAL_COLUMN_INDEX = 255;
private const int MAX_COLUMN_INDEX = 16383;
private static Dictionary<int, string> _IntMappingAlphabet;
private static Dictionary<string, int> _AlphabetMappingInt;
static Helpers()
{
for (int i = 0; i <= 255; i++)
if (_IntMappingAlphabet == null && _AlphabetMappingInt == null)
{
_IntMappingAlphabet.Add(i, IntToLetters(i));
_AlphabetMappingInt.Add(IntToLetters(i), i);
_IntMappingAlphabet = new Dictionary<int, string>();
_AlphabetMappingInt = new Dictionary<string, int>();
for (int i = 0; i <= GENERAL_COLUMN_INDEX; i++)
{
_IntMappingAlphabet.Add(i, IntToLetters(i));
_AlphabetMappingInt.Add(IntToLetters(i), i);
}
}
}
internal static string GetAlphabetColumnName(int ColumnIndex) => _IntMappingAlphabet[ColumnIndex];
internal static int GetColumnIndex(string columnName) => _AlphabetMappingInt[columnName];
public static string GetAlphabetColumnName(int columnIndex)
{
CheckAndSetMaxColumnIndex(columnIndex);
return _IntMappingAlphabet[columnIndex];
}
public static int GetColumnIndex(string columnName)
{
var columnIndex = _AlphabetMappingInt[columnName];
CheckAndSetMaxColumnIndex(columnIndex);
return columnIndex;
}
private static void CheckAndSetMaxColumnIndex(int columnIndex)
{
if (columnIndex >= _IntMappingAlphabet.Count)
{
if (columnIndex > MAX_COLUMN_INDEX)
throw new InvalidDataException($"ColumnIndex {columnIndex} over excel vaild max index.");
for (int i = _IntMappingAlphabet.Count; i <= columnIndex; i++)
{
_IntMappingAlphabet.Add(i, IntToLetters(i));
_AlphabetMappingInt.Add(IntToLetters(i), i);
}
}
}
internal static string IntToLetters(int value)
{

View File

@ -23,6 +23,18 @@ namespace MiniExcelLibs.Tests
this.output = output;
}
/// <summary>
/// https://github.com/shps951023/MiniExcel/issues/208
/// </summary>
[Fact]
public void Issue208()
{
var path = @"..\..\..\..\..\samples\xlsx\TestIssue208.xlsx";
var columns = MiniExcel.GetColumns(path).ToList();
Assert.Equal(16384, columns.Count);
Assert.Equal("XFD", columns[16383]);
}
/// <summary>
/// https://github.com/shps951023/MiniExcel/issues/206
/// </summary>

View File

@ -21,21 +21,52 @@ namespace MiniExcelLibs.Tests.Utils
internal static class Helpers
{
private static Dictionary<int, string> _IntMappingAlphabet = new Dictionary<int, string>();
private static Dictionary<string, int> _AlphabetMappingInt = new Dictionary<string, int>();
static Helpers()
{
for (int i = 0; i <= 255; i++)
{
_IntMappingAlphabet.Add(i, IntToLetters(i));
_AlphabetMappingInt.Add(IntToLetters(i), i);
}
}
private const int GENERAL_COLUMN_INDEX = 255;
private const int MAX_COLUMN_INDEX = 16383;
private static Dictionary<int, string> _IntMappingAlphabet;
private static Dictionary<string, int> _AlphabetMappingInt;
static Helpers()
{
if (_IntMappingAlphabet == null && _AlphabetMappingInt == null)
{
_IntMappingAlphabet = new Dictionary<int, string>();
_AlphabetMappingInt = new Dictionary<string, int>();
for (int i = 0; i <= GENERAL_COLUMN_INDEX; i++)
{
_IntMappingAlphabet.Add(i, IntToLetters(i));
_AlphabetMappingInt.Add(IntToLetters(i), i);
}
}
}
public static string GetAlphabetColumnName(int ColumnIndex) => _IntMappingAlphabet[ColumnIndex];
public static int GetColumnIndex(string columnName) => _AlphabetMappingInt[columnName];
public static string GetAlphabetColumnName(int columnIndex)
{
CheckAndSetMaxColumnIndex(columnIndex);
return _IntMappingAlphabet[columnIndex];
}
internal static string IntToLetters(int value)
public static int GetColumnIndex(string columnName)
{
var columnIndex = _AlphabetMappingInt[columnName];
CheckAndSetMaxColumnIndex(columnIndex);
return columnIndex;
}
private static void CheckAndSetMaxColumnIndex(int columnIndex)
{
if (columnIndex >= _IntMappingAlphabet.Count)
{
if (columnIndex > MAX_COLUMN_INDEX)
throw new InvalidDataException($"ColumnIndex {columnIndex} over excel vaild max index.");
for (int i = _IntMappingAlphabet.Count; i <= columnIndex; i++)
{
_IntMappingAlphabet.Add(i, IntToLetters(i));
_AlphabetMappingInt.Add(IntToLetters(i), i);
}
}
}
internal static string IntToLetters(int value)
{
value = value + 1;
string result = string.Empty;