diff --git a/README.md b/README.md index 27d90bb..36e5098 100644 --- a/README.md +++ b/README.md @@ -910,6 +910,25 @@ MiniExcel.SaveAs(path, value,excelType:ExcelType.CSV, configuration: config); +### DataReader + +#### 1. GetReader +Since 1.23.0, you can GetDataReader + +```csharp + using (var reader = MiniExcel.GetReader(path,true)) + { + while (reader.Read()) + { + for (int i = 0; i < reader.FieldCount; i++) + { + var value = reader.GetValue(i); + } + } + } +``` + + ### Async @@ -993,6 +1012,8 @@ MiniExcel.Query(path, configuration: config); + + ### Examples: #### 1. SQLite & Dapper `Large Size File` SQL Insert Avoid OOM diff --git a/README.zh-CN.md b/README.zh-CN.md index 9c03172..4b36f8d 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -914,6 +914,29 @@ MiniExcel.SaveAs(path, value,excelType:ExcelType.CSV, configuration: config); +### DataReader + +#### 1. GetReader + +从 1.23.0 版本开始能获取 DataReader + +```csharp + using (var reader = MiniExcel.GetReader(path,true)) + { + while (reader.Read()) + { + for (int i = 0; i < reader.FieldCount; i++) + { + var value = reader.GetValue(i); + } + } + } +``` + + + + + ### 异步 Async 从 v0.17.0 版本开始支持异步 (感谢[isdaniel ( SHIH,BING-SIOU)](https://github.com/isdaniel)) diff --git a/README.zh-Hant.md b/README.zh-Hant.md index d3ce4e8..cda91e6 100644 --- a/README.zh-Hant.md +++ b/README.zh-Hant.md @@ -922,6 +922,26 @@ MiniExcel.SaveAs(path, value,excelType:ExcelType.CSV, configuration: config); ``` +### DataReader + +#### 1. GetReader + +从 1.23.0 版本开始能获取 DataReader + +```csharp + using (var reader = MiniExcel.GetReader(path,true)) + { + while (reader.Read()) + { + for (int i = 0; i < reader.FieldCount; i++) + { + var value = reader.GetValue(i); + } + } + } +``` + + ### 異步 Async diff --git a/docs/README.md b/docs/README.md index d01109f..c16222d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,7 +16,13 @@ --- + +### 1.23.0 +- [New] Support `GetReader` method #328 #290 (Thanks [杨福来 Yang](https://github.com/yfl8910) ) + + ### 1.22.0 + - [New] SaveAs support to custom CultureInfo #316 - [New] Query support to custom CultureInfo #316 - [New] New efficiency byte array Converter #327 diff --git a/docs/README.zh-CN.md b/docs/README.zh-CN.md index 26fe948..25b057f 100644 --- a/docs/README.zh-CN.md +++ b/docs/README.zh-CN.md @@ -24,6 +24,9 @@ --- +### 1.23.0 +- [New] 新增 `GetReader` 方法 #328 #290 (感谢 [杨福来 Yang](https://github.com/yfl8910) ) + ### 1.22.0 - [New] SaveAs 支持自定义 CultureInfo #316 - [New] Query 支持自定义 CultureInfo #316 diff --git a/docs/README.zh-Hant.md b/docs/README.zh-Hant.md index 7e4ff97..6695746 100644 --- a/docs/README.zh-Hant.md +++ b/docs/README.zh-Hant.md @@ -17,7 +17,13 @@ --- + + +### 1.23.0 +- [New] 新增 `GetReader` 方法 #328 #290 (感謝 [楊福來 Yang](https://github.com/yfl8910) ) + ### 1.22.0 + - [New] SaveAs 支持自定義 CultureInfo #316 - [New] Query 支持自定義 CultureInfo #316 - [New] 新 byte array 轉換器 #327 diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs index 057eb6a..f577f4c 100644 --- a/src/MiniExcel/MiniExcel.cs +++ b/src/MiniExcel/MiniExcel.cs @@ -12,6 +12,17 @@ public static partial class MiniExcel { + public static MiniExcelDataReader GetReader(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + { + var stream = FileHelper.OpenSharedRead(path); + return new MiniExcelDataReader(stream, useHeaderRow, sheetName, excelType, startCell, configuration); + } + + public static MiniExcelDataReader GetDataReader(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + { + return new MiniExcelDataReader(stream, useHeaderRow, sheetName, excelType, startCell, configuration); + } + public static void SaveAs(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null) { if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm") diff --git a/src/MiniExcel/MiniExcelDataReader.cs b/src/MiniExcel/MiniExcelDataReader.cs new file mode 100644 index 0000000..da986fd --- /dev/null +++ b/src/MiniExcel/MiniExcelDataReader.cs @@ -0,0 +1,186 @@ +namespace MiniExcelLibs +{ + using MiniExcelLibs.Utils; + using System; + using System.Collections.Generic; + using System.Data; + using System.IO; + using System.Linq; + + public class MiniExcelDataReader : IDataReader + { + private readonly IEnumerator> _source; + private readonly int _fieldCount; + private readonly List _keys; + private readonly Stream _stream; + private bool _isFirst = true; + + internal MiniExcelDataReader(Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) + { + _stream = stream; + _source = MiniExcel.Query(_stream, useHeaderRow, sheetName, excelType, startCell, configuration).Cast>().GetEnumerator(); + var isNext = _source.MoveNext(); + if (isNext) + { + _keys = _source.Current.Keys.ToList(); + _fieldCount = _keys.Count; + } + } + + public void Dispose() + { + _stream.Dispose(); + } + + public object GetValue(int i) + { + return _source.Current[_keys[i]]; + } + + public int FieldCount + { + get { return _fieldCount; } + } + + public bool Read() + { + if (_isFirst) + { + _isFirst = false; + return true; + } + return _source.MoveNext(); + } + + public string GetName(int i) + { + return _keys[i]; + } + + public int GetOrdinal(string name) + { + var i = _keys.IndexOf(name); + return _keys.IndexOf(name); + } + + public void Close() + { + throw new NotImplementedException(); + } + + public int Depth => throw new NotImplementedException(); + + public bool IsClosed => throw new NotImplementedException(); + + public int RecordsAffected => throw new NotImplementedException(); + + public object this[string name] => throw new NotImplementedException(); + + public object this[int i] => throw new NotImplementedException(); + + public DataTable GetSchemaTable() + { + throw new NotImplementedException(); + } + + public bool NextResult() + { + throw new NotImplementedException(); + } + + public bool GetBoolean(int i) + { + throw new NotImplementedException(); + } + + public byte GetByte(int i) + { + throw new NotImplementedException(); + } + + public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) + { + throw new NotImplementedException(); + } + + public char GetChar(int i) + { + throw new NotImplementedException(); + } + + public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) + { + throw new NotImplementedException(); + } + + public IDataReader GetData(int i) + { + throw new NotImplementedException(); + } + + public string GetDataTypeName(int i) + { + throw new NotImplementedException(); + } + + public DateTime GetDateTime(int i) + { + throw new NotImplementedException(); + } + + public decimal GetDecimal(int i) + { + throw new NotImplementedException(); + } + + public double GetDouble(int i) + { + throw new NotImplementedException(); + } + + public Type GetFieldType(int i) + { + throw new NotImplementedException(); + } + + public float GetFloat(int i) + { + throw new NotImplementedException(); + } + + public Guid GetGuid(int i) + { + throw new NotImplementedException(); + } + + public short GetInt16(int i) + { + throw new NotImplementedException(); + } + + public int GetInt32(int i) + { + throw new NotImplementedException(); + } + + public long GetInt64(int i) + { + throw new NotImplementedException(); + } + + public string GetString(int i) + { + throw new NotImplementedException(); + } + + public int GetValues(object[] values) + { + throw new NotImplementedException(); + } + + public bool IsDBNull(int i) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/MiniExcel/MiniExcelLibs.csproj b/src/MiniExcel/MiniExcelLibs.csproj index 539655f..7bda47f 100644 --- a/src/MiniExcel/MiniExcelLibs.csproj +++ b/src/MiniExcel/MiniExcelLibs.csproj @@ -1,7 +1,7 @@  net45;netstandard2.0;net5.0 - 1.22.0 + 1.23.0 MiniExcel diff --git a/tests/MiniExcelTests/MiniExcelIssueTests.cs b/tests/MiniExcelTests/MiniExcelIssueTests.cs index dea0365..f3e6f13 100644 --- a/tests/MiniExcelTests/MiniExcelIssueTests.cs +++ b/tests/MiniExcelTests/MiniExcelIssueTests.cs @@ -31,6 +31,45 @@ namespace MiniExcelLibs.Tests this.output = output; } + [Fact] + public void TestIssue328() + { + var path = PathHelper.GetTempFilePath(); + var value = new[] { + new { id=1,name="Jack",indate=new DateTime(2022,5,13), file = File.ReadAllBytes(PathHelper.GetFile("images/TestIssue327.png")) }, + new { id=2,name="Henry",indate=new DateTime(2022,4,10), file = File.ReadAllBytes(PathHelper.GetFile("other/TestIssue327.txt")) }, + }; + MiniExcel.SaveAs(path, value); + + var rowIndx = 0; + using (var reader = MiniExcel.GetReader(path,true)) + { + Assert.Equal("id", reader.GetName(0)); + Assert.Equal("name", reader.GetName(1)); + Assert.Equal("indate", reader.GetName(2)); + Assert.Equal("file", reader.GetName(3)); + + while (reader.Read()) + { + for (int i = 0; i < reader.FieldCount; i++) + { + var v = reader.GetValue(i); + if (rowIndx==0 && i==0) Assert.Equal((double)1,v); + if (rowIndx == 0 && i == 1) Assert.Equal("Jack", v); + if (rowIndx == 0 && i == 2) Assert.Equal(new DateTime(2022, 5, 13), v); + if (rowIndx == 0 && i == 3) Assert.Equal(File.ReadAllBytes(PathHelper.GetFile("images/TestIssue327.png")), v); + if (rowIndx == 1 && i == 0) Assert.Equal((double)2, v); + if (rowIndx == 1 && i == 1) Assert.Equal("Henry", v); + if (rowIndx == 1 && i == 2) Assert.Equal(new DateTime(2022, 4, 10), v); + if (rowIndx == 1 && i == 3) Assert.Equal(File.ReadAllBytes(PathHelper.GetFile("other/TestIssue327.txt")), v); + } + rowIndx++; + } + } + + //TODO:How to resolve empty body sheet? + } + [Fact] public void TestIssue327() {