From 67f72f1fee2f3912a4174dedac16187ae5cd4c3c Mon Sep 17 00:00:00 2001 From: izanhzh Date: Thu, 2 Jan 2025 17:49:25 +0800 Subject: [PATCH 1/9] feat(MiniExcelDataReaderBase): Add asynchronous support --- src/MiniExcel/Csv/CsvWriter.cs | 4 +- src/MiniExcel/IMiniExcelDataReader.cs | 29 +++ src/MiniExcel/MiniExcelDataReader.cs | 1 + src/MiniExcel/MiniExcelDataReaderBase.cs | 166 +++++++++++++++++- src/MiniExcel/MiniExcelTask.cs | 59 +++++++ .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 130 +++++++++++++- .../MiniExcelInsertSheetTests.cs | 41 +++++ 7 files changed, 417 insertions(+), 13 deletions(-) create mode 100644 src/MiniExcel/IMiniExcelDataReader.cs create mode 100644 src/MiniExcel/MiniExcelTask.cs create mode 100644 tests/MiniExcelTests/MiniExcelInsertSheetTests.cs diff --git a/src/MiniExcel/Csv/CsvWriter.cs b/src/MiniExcel/Csv/CsvWriter.cs index ee50da7d..bc6d1cb5 100644 --- a/src/MiniExcel/Csv/CsvWriter.cs +++ b/src/MiniExcel/Csv/CsvWriter.cs @@ -140,10 +140,8 @@ public void Insert() await Task.Run(() => SaveAs(), cancellationToken).ConfigureAwait(false); } - private void GenerateSheetByIDataReader(object value, string seperator, string newLine, StreamWriter writer) + private void GenerateSheetByIDataReader(IDataReader reader, string seperator, string newLine, StreamWriter writer) { - var reader = (IDataReader)value; - int fieldCount = reader.FieldCount; if (fieldCount == 0) throw new InvalidDataException("fieldCount is 0"); diff --git a/src/MiniExcel/IMiniExcelDataReader.cs b/src/MiniExcel/IMiniExcelDataReader.cs new file mode 100644 index 00000000..0ecd59cc --- /dev/null +++ b/src/MiniExcel/IMiniExcelDataReader.cs @@ -0,0 +1,29 @@ +using System.Data; +using System.Threading; +using System.Threading.Tasks; + +namespace MiniExcelLibs +{ + public interface IMiniExcelDataReader : IDataReader + { + Task CloseAsync(); + + Task GetNameAsync(int i); + + Task GetNameAsync(int i, CancellationToken cancellationToken); + + Task GetValueAsync(int i); + + Task GetValueAsync(int i, CancellationToken cancellationToken); + + Task NextResultAsync(); + + Task NextResultAsync(CancellationToken cancellationToken); + + Task ReadAsync(); + + Task ReadAsync(CancellationToken cancellationToken); + + Task DisposeAsync(); + } +} diff --git a/src/MiniExcel/MiniExcelDataReader.cs b/src/MiniExcel/MiniExcelDataReader.cs index a2241f62..f2ae9a74 100644 --- a/src/MiniExcel/MiniExcelDataReader.cs +++ b/src/MiniExcel/MiniExcelDataReader.cs @@ -65,6 +65,7 @@ public override string GetName(int i) { return _keys[i]; } + /// protected override void Dispose(bool disposing) { diff --git a/src/MiniExcel/MiniExcelDataReaderBase.cs b/src/MiniExcel/MiniExcelDataReaderBase.cs index 3832bf6d..6f03f8a1 100644 --- a/src/MiniExcel/MiniExcelDataReaderBase.cs +++ b/src/MiniExcel/MiniExcelDataReaderBase.cs @@ -2,11 +2,13 @@ { using System; using System.Data; + using System.Threading; + using System.Threading.Tasks; /// - /// IDataReader Base Class + /// IMiniExcelDataReader Base Class /// - public abstract class MiniExcelDataReaderBase : IDataReader + public abstract class MiniExcelDataReaderBase : IMiniExcelDataReader { /// /// @@ -202,6 +204,36 @@ public abstract class MiniExcelDataReaderBase : IDataReader /// public virtual bool NextResult() => false; + /// + /// + /// + /// + public Task NextResultAsync() => NextResultAsync(CancellationToken.None); + + /// + /// + /// + /// + /// + public virtual Task NextResultAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return MiniExcelTask.FromCanceled(new CancellationToken(true)); + } + else + { + try + { + return NextResult() ? Task.FromResult(true) : Task.FromResult(false); + } + catch (Exception e) + { + return MiniExcelTask.FromException(e); + } + } + } + /// /// /// @@ -209,6 +241,38 @@ public abstract class MiniExcelDataReaderBase : IDataReader /// public abstract string GetName(int i); + /// + /// + /// + /// + /// + public Task GetNameAsync(int i) => GetNameAsync(i, CancellationToken.None); + + /// + /// + /// + /// + /// + /// + public virtual Task GetNameAsync(int i, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return MiniExcelTask.FromCanceled(new CancellationToken(true)); + } + else + { + try + { + return Task.FromResult(GetName(i)); + } + catch (Exception e) + { + return MiniExcelTask.FromException(e); + } + } + } + /// /// /// @@ -216,12 +280,74 @@ public abstract class MiniExcelDataReaderBase : IDataReader /// public abstract object GetValue(int i); + /// + /// + /// + /// + /// + public Task GetValueAsync(int i) => GetValueAsync(i, CancellationToken.None); + + /// + /// + /// + /// + /// + /// + public virtual Task GetValueAsync(int i, CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return MiniExcelTask.FromCanceled(new CancellationToken(true)); + } + else + { + try + { + return Task.FromResult(GetValue(i)); + } + catch (Exception e) + { + return MiniExcelTask.FromException(e); + } + } + } + /// /// /// /// public abstract bool Read(); + /// + /// + /// + /// + public Task ReadAsync() => ReadAsync(CancellationToken.None); + + /// + /// + /// + /// + /// + public virtual Task ReadAsync(CancellationToken cancellationToken) + { + if (cancellationToken.IsCancellationRequested) + { + return MiniExcelTask.FromCanceled(new CancellationToken(true)); + } + else + { + try + { + return NextResult() ? Task.FromResult(true) : Task.FromResult(false); + } + catch (Exception e) + { + return MiniExcelTask.FromException(e); + } + } + } + /// /// /// @@ -233,10 +359,18 @@ public virtual void Close() /// /// /// - /// - protected virtual void Dispose(bool disposing) + /// + public virtual Task CloseAsync() { - + try + { + Close(); + return MiniExcelTask.CompletedTask; + } + catch (Exception e) + { + return MiniExcelTask.FromException(e); + } } /// @@ -247,5 +381,27 @@ public void Dispose() Dispose(true); GC.SuppressFinalize(this); } + + /// + /// + /// + /// + public virtual Task DisposeAsync() + { + Dispose(); + return MiniExcelTask.CompletedTask; + } + + /// + /// + /// + /// + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Close(); + } + } } } diff --git a/src/MiniExcel/MiniExcelTask.cs b/src/MiniExcel/MiniExcelTask.cs new file mode 100644 index 00000000..06f8d414 --- /dev/null +++ b/src/MiniExcel/MiniExcelTask.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace MiniExcelLibs +{ + internal class MiniExcelTask + { +#if NET45 + public static Task CompletedTask = Task.FromResult(0); +#else + public static Task CompletedTask = Task.CompletedTask; +#endif + + public static Task FromException(Exception exception) + { +#if NET45 + var tcs = new TaskCompletionSource(); + tcs.SetException(exception); + return tcs.Task; +#else + return Task.FromException(exception); +#endif + } + + public static Task FromException(Exception exception) + { +#if NET45 + var tcs = new TaskCompletionSource(); + tcs.SetException(exception); + return tcs.Task; +#else + return Task.FromException(exception); +#endif + } + + public static Task FromCanceled(CancellationToken cancellationToken) + { +#if NET45 + var tcs = new TaskCompletionSource(); + cancellationToken.Register(() => tcs.SetCanceled()); + return tcs.Task; +#else + return Task.FromCanceled(cancellationToken); +#endif + } + + public static Task FromCanceled(CancellationToken cancellationToken) + { +#if NET45 + var tcs = new TaskCompletionSource(); + cancellationToken.Register(() => tcs.SetCanceled()); + return tcs.Task; +#else + return Task.FromCanceled(cancellationToken); +#endif + } + } +} diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 07b3f73f..c86220da 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -1,12 +1,10 @@ -using MiniExcelLibs.Attributes; -using MiniExcelLibs.OpenXml.Constants; +using MiniExcelLibs.OpenXml.Constants; using MiniExcelLibs.Utils; using MiniExcelLibs.Zip; using System; using System.Collections; using System.Collections.Generic; using System.Data; -using System.Globalization; using System.IO.Compression; using System.Linq; using System.Text; @@ -100,6 +98,12 @@ private async Task WriteDimensionAsync(MiniExcelAsyncStreamWriter writer, int ma private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter writer, IDataReader reader) { + if (reader is IMiniExcelDataReader miniExcelDataReader) + { + await GenerateSheetByIMiniExcelDataReaderAsync(writer, miniExcelDataReader); + return; + } + long dimensionPlaceholderPostition = 0; await writer.WriteAsync(WorksheetXml.StartWorksheet); var yIndex = 1; @@ -157,7 +161,10 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr if (_printHeader) { await PrintHeaderAsync(writer, props); - yIndex++; + if (props.Count > 0) + { + yIndex++; + } } while (reader.Read()) @@ -208,6 +215,119 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr } } + private async Task GenerateSheetByIMiniExcelDataReaderAsync(MiniExcelAsyncStreamWriter writer, IMiniExcelDataReader reader) + { + long dimensionPlaceholderPostition = 0; + await writer.WriteAsync(WorksheetXml.StartWorksheet); + var yIndex = 1; + int maxColumnIndex; + int maxRowIndex; + ExcelWidthCollection widths = null; + long columnWidthsPlaceholderPosition = 0; + { + if (_configuration.FastMode) + { + dimensionPlaceholderPostition = await WriteDimensionPlaceholderAsync(writer); + } + + var props = new List(); + for (var i = 0; i < reader.FieldCount; i++) + { + var columnName = await reader.GetNameAsync(i); + + if (!_configuration.DynamicColumnFirst) + { + var prop = GetColumnInfosFromDynamicConfiguration(columnName); + props.Add(prop); + continue; + } + + if (_configuration + .DynamicColumns + .Any(a => string.Equals( + a.Key, + columnName, + StringComparison.OrdinalIgnoreCase))) + + { + var prop = GetColumnInfosFromDynamicConfiguration(columnName); + props.Add(prop); + } + } + maxColumnIndex = props.Count; + + //sheet view + await writer.WriteAsync(GetSheetViews()); + + if (_configuration.EnableAutoWidth) + { + columnWidthsPlaceholderPosition = await WriteColumnWidthPlaceholdersAsync(writer, props); + widths = new ExcelWidthCollection(_configuration.MinWidth, _configuration.MaxWidth, props); + } + else + { + await WriteColumnsWidthsAsync(writer, ExcelColumnWidth.FromProps(props)); + } + + await writer.WriteAsync(WorksheetXml.StartSheetData); + int fieldCount = reader.FieldCount; + if (_printHeader) + { + await PrintHeaderAsync(writer, props); + if (props.Count > 0) + { + yIndex++; + } + } + + while (await reader.ReadAsync()) + { + await writer.WriteAsync(WorksheetXml.StartRow(yIndex)); + var xIndex = 1; + for (int i = 0; i < fieldCount; i++) + { + object cellValue; + + if (_configuration.DynamicColumnFirst) + { + var columnIndex = reader.GetOrdinal(props[i].Key.ToString()); + cellValue = await reader.GetValueAsync(columnIndex); + } + else + { + cellValue = await reader.GetValueAsync(i); + } + + await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[i], widths); + xIndex++; + } + await writer.WriteAsync(WorksheetXml.EndRow); + yIndex++; + } + + // Subtract 1 because cell indexing starts with 1 + maxRowIndex = yIndex - 1; + } + + await writer.WriteAsync(WorksheetXml.EndSheetData); + + if (_configuration.AutoFilter) + { + await writer.WriteAsync(WorksheetXml.Autofilter(GetDimensionRef(maxRowIndex, maxColumnIndex))); + } + + await writer.WriteAndFlushAsync(WorksheetXml.EndWorksheet); + + if (_configuration.FastMode) + { + await WriteDimensionAsync(writer, maxRowIndex, maxColumnIndex, dimensionPlaceholderPostition); + } + if (_configuration.EnableAutoWidth) + { + await OverWriteColumnWidthPlaceholdersAsync(writer, columnWidthsPlaceholderPosition, widths.Columns); + } + } + private async Task GenerateSheetByEnumerableAsync(MiniExcelAsyncStreamWriter writer, IEnumerable values) { var maxColumnIndex = 0; @@ -576,7 +696,7 @@ private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowInde //ignored } } - + await writer.WriteAsync(WorksheetXml.Cell(columnReference, dataType, styleIndex, cellValue, preserveSpace: preserveSpace, columnType: columnType)); widthCollection?.AdjustWidth(cellIndex, cellValue); } diff --git a/tests/MiniExcelTests/MiniExcelInsertSheetTests.cs b/tests/MiniExcelTests/MiniExcelInsertSheetTests.cs new file mode 100644 index 00000000..21440eba --- /dev/null +++ b/tests/MiniExcelTests/MiniExcelInsertSheetTests.cs @@ -0,0 +1,41 @@ +using MiniExcelLibs; +using System; +using System.IO; +using Xunit; + +namespace MiniExcelTests +{ + public class MiniExcelInsertSheetTests + { + [Fact] + public async void InsertSheetTestAsync() + { + // if (File.Exists(@"C:\Users\huangzhenhua\Desktop\1.xlsx")) + // { + // File.Delete(@"C:\Users\huangzhenhua\Desktop\1.xlsx"); + // } + // File.Copy(@"C:\Users\huangzhenhua\Desktop\3 - 副本.xlsx", @"C:\Users\huangzhenhua\Desktop\1.xlsx"); + // var dt = await MiniExcelLibs.MiniExcel.QueryAsDataTableAsync(@"C:\Users\huangzhenhua\Desktop\1.xlsx", true); + + // MiniExcelLibs.MiniExcel.InsertSheet(@"C:\Users\huangzhenhua\Desktop\1.xlsx", dt, sheetName: "Sheet3", overwriteSheet: true); + + string filePath = Path.Combine(@"C:\Users\huangzhenhua\Desktop\1.csv"); + var objList = new[] { + new { ID=1,Name ="Frank",InDate=new DateTime(2021,06,07)}, + new { ID=2,Name ="Gloria",InDate=new DateTime(2022,05,03)}, + }; + using (var stream = File.OpenWrite(filePath)) + { + MiniExcelLibs.MiniExcel.SaveAs(stream, objList, true, "data", ExcelType.CSV); + } + objList = new[] { + new { ID=3,Name ="Frank",InDate=new DateTime(2021,06,07)}, + new { ID=4,Name ="Gloria",InDate=new DateTime(2022,05,03)}, + }; + using (var stream = File.OpenWrite(filePath)) + { + MiniExcelLibs.MiniExcel.Insert(stream, objList, "data", ExcelType.CSV); + } + } + } +} From 8c4f48ffbceacc2ac43513dc5a620cab4d856dd3 Mon Sep 17 00:00:00 2001 From: izanhzh Date: Thu, 2 Jan 2025 18:09:16 +0800 Subject: [PATCH 2/9] fix `ReadAsync` bug --- src/MiniExcel/MiniExcelDataReaderBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MiniExcel/MiniExcelDataReaderBase.cs b/src/MiniExcel/MiniExcelDataReaderBase.cs index 6f03f8a1..5491d1ce 100644 --- a/src/MiniExcel/MiniExcelDataReaderBase.cs +++ b/src/MiniExcel/MiniExcelDataReaderBase.cs @@ -339,7 +339,7 @@ public virtual Task ReadAsync(CancellationToken cancellationToken) { try { - return NextResult() ? Task.FromResult(true) : Task.FromResult(false); + return Read() ? Task.FromResult(true) : Task.FromResult(false); } catch (Exception e) { From 6aa688dd352eb73aafa9fb3a75cf6baba2538020 Mon Sep 17 00:00:00 2001 From: izanhzh Date: Thu, 2 Jan 2025 18:20:17 +0800 Subject: [PATCH 3/9] remove the error submission code --- .../MiniExcelInsertSheetTests.cs | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 tests/MiniExcelTests/MiniExcelInsertSheetTests.cs diff --git a/tests/MiniExcelTests/MiniExcelInsertSheetTests.cs b/tests/MiniExcelTests/MiniExcelInsertSheetTests.cs deleted file mode 100644 index 21440eba..00000000 --- a/tests/MiniExcelTests/MiniExcelInsertSheetTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using MiniExcelLibs; -using System; -using System.IO; -using Xunit; - -namespace MiniExcelTests -{ - public class MiniExcelInsertSheetTests - { - [Fact] - public async void InsertSheetTestAsync() - { - // if (File.Exists(@"C:\Users\huangzhenhua\Desktop\1.xlsx")) - // { - // File.Delete(@"C:\Users\huangzhenhua\Desktop\1.xlsx"); - // } - // File.Copy(@"C:\Users\huangzhenhua\Desktop\3 - 副本.xlsx", @"C:\Users\huangzhenhua\Desktop\1.xlsx"); - // var dt = await MiniExcelLibs.MiniExcel.QueryAsDataTableAsync(@"C:\Users\huangzhenhua\Desktop\1.xlsx", true); - - // MiniExcelLibs.MiniExcel.InsertSheet(@"C:\Users\huangzhenhua\Desktop\1.xlsx", dt, sheetName: "Sheet3", overwriteSheet: true); - - string filePath = Path.Combine(@"C:\Users\huangzhenhua\Desktop\1.csv"); - var objList = new[] { - new { ID=1,Name ="Frank",InDate=new DateTime(2021,06,07)}, - new { ID=2,Name ="Gloria",InDate=new DateTime(2022,05,03)}, - }; - using (var stream = File.OpenWrite(filePath)) - { - MiniExcelLibs.MiniExcel.SaveAs(stream, objList, true, "data", ExcelType.CSV); - } - objList = new[] { - new { ID=3,Name ="Frank",InDate=new DateTime(2021,06,07)}, - new { ID=4,Name ="Gloria",InDate=new DateTime(2022,05,03)}, - }; - using (var stream = File.OpenWrite(filePath)) - { - MiniExcelLibs.MiniExcel.Insert(stream, objList, "data", ExcelType.CSV); - } - } - } -} From 2163b9df7d1c6c44c76dd07840ef785c6c5bf846 Mon Sep 17 00:00:00 2001 From: izanhzh Date: Fri, 3 Jan 2025 08:49:33 +0800 Subject: [PATCH 4/9] add unit test --- src/MiniExcel/IMiniExcelDataReader.cs | 9 ++++++- src/MiniExcel/MiniExcelDataReaderBase.cs | 13 +++++++++ .../MiniExcelOpenXmlAsyncTests.cs | 27 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/MiniExcel/IMiniExcelDataReader.cs b/src/MiniExcel/IMiniExcelDataReader.cs index 0ecd59cc..1cc280d5 100644 --- a/src/MiniExcel/IMiniExcelDataReader.cs +++ b/src/MiniExcel/IMiniExcelDataReader.cs @@ -1,10 +1,15 @@ -using System.Data; +using System; +using System.Data; using System.Threading; using System.Threading.Tasks; namespace MiniExcelLibs { +#if !NET8_0_OR_GREATER public interface IMiniExcelDataReader : IDataReader +#else + public interface IMiniExcelDataReader : IDataReader, IAsyncDisposable +#endif { Task CloseAsync(); @@ -24,6 +29,8 @@ public interface IMiniExcelDataReader : IDataReader Task ReadAsync(CancellationToken cancellationToken); +#if !NET8_0_OR_GREATER Task DisposeAsync(); +#endif } } diff --git a/src/MiniExcel/MiniExcelDataReaderBase.cs b/src/MiniExcel/MiniExcelDataReaderBase.cs index 5491d1ce..83ecc2ad 100644 --- a/src/MiniExcel/MiniExcelDataReaderBase.cs +++ b/src/MiniExcel/MiniExcelDataReaderBase.cs @@ -382,6 +382,18 @@ public void Dispose() GC.SuppressFinalize(this); } +#if NET8_0_OR_GREATER + /// + /// + /// + /// + /// + public virtual ValueTask DisposeAsync() + { + Dispose(); + return default; + } +#else /// /// /// @@ -391,6 +403,7 @@ public virtual Task DisposeAsync() Dispose(); return MiniExcelTask.CompletedTask; } +#endif /// /// diff --git a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs index b49e73c9..07d68332 100644 --- a/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs +++ b/tests/MiniExcelTests/MiniExcelOpenXmlAsyncTests.cs @@ -1489,5 +1489,32 @@ public async Task DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingDataTab Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[1]["Column4"]); } } + + [Fact] + public async Task SaveAsByMiniExcelDataReader() + { + var path1 = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx"); + + var values = new List() + { + new Demo { Column1= "MiniExcel" ,Column2 = 1 }, + new Demo { Column1 = "Github", Column2 = 2 } + }; + await MiniExcel.SaveAsAsync(path1, values); + + var reader = (IMiniExcelDataReader)MiniExcel.GetReader(path1, true); + + var path2 = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx"); + + await MiniExcel.SaveAsAsync(path2, reader); + + var results = MiniExcel.Query(path2); + + Assert.True(results.Count() == 2); + Assert.True(results.First().Column1 == "MiniExcel"); + Assert.True(results.First().Column2 == 1); + Assert.True(results.Last().Column1 == "Github"); + Assert.True(results.Last().Column2 == 2); + } } } \ No newline at end of file From f15b1f9af692be081b39608b82200ace47db3f9b Mon Sep 17 00:00:00 2001 From: izanhzh Date: Fri, 3 Jan 2025 09:16:21 +0800 Subject: [PATCH 5/9] optimization cancellation --- src/MiniExcel/MiniExcelDataReaderBase.cs | 8 ++++---- .../OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/MiniExcel/MiniExcelDataReaderBase.cs b/src/MiniExcel/MiniExcelDataReaderBase.cs index 83ecc2ad..71ab054c 100644 --- a/src/MiniExcel/MiniExcelDataReaderBase.cs +++ b/src/MiniExcel/MiniExcelDataReaderBase.cs @@ -219,7 +219,7 @@ public virtual Task NextResultAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { - return MiniExcelTask.FromCanceled(new CancellationToken(true)); + return MiniExcelTask.FromCanceled(cancellationToken); } else { @@ -258,7 +258,7 @@ public virtual Task GetNameAsync(int i, CancellationToken cancellationTo { if (cancellationToken.IsCancellationRequested) { - return MiniExcelTask.FromCanceled(new CancellationToken(true)); + return MiniExcelTask.FromCanceled(cancellationToken); } else { @@ -297,7 +297,7 @@ public virtual Task GetValueAsync(int i, CancellationToken cancellationT { if (cancellationToken.IsCancellationRequested) { - return MiniExcelTask.FromCanceled(new CancellationToken(true)); + return MiniExcelTask.FromCanceled(cancellationToken); } else { @@ -333,7 +333,7 @@ public virtual Task ReadAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { - return MiniExcelTask.FromCanceled(new CancellationToken(true)); + return MiniExcelTask.FromCanceled(cancellationToken); } else { diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index c86220da..30faedcb 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -56,7 +56,7 @@ private async Task CreateSheetXmlAsync(object value, string sheetPath, Cancellat switch (value) { case IDataReader dataReader: - await GenerateSheetByIDataReaderAsync(writer, dataReader); + await GenerateSheetByIDataReaderAsync(writer, dataReader, cancellationToken); break; case IEnumerable enumerable: await GenerateSheetByEnumerableAsync(writer, enumerable); @@ -96,11 +96,11 @@ private async Task WriteDimensionAsync(MiniExcelAsyncStreamWriter writer, int ma writer.SetPosition(position); } - private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter writer, IDataReader reader) + private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter writer, IDataReader reader, CancellationToken cancellationToken) { if (reader is IMiniExcelDataReader miniExcelDataReader) { - await GenerateSheetByIMiniExcelDataReaderAsync(writer, miniExcelDataReader); + await GenerateSheetByIMiniExcelDataReaderAsync(writer, miniExcelDataReader, cancellationToken); return; } @@ -215,7 +215,7 @@ private async Task GenerateSheetByIDataReaderAsync(MiniExcelAsyncStreamWriter wr } } - private async Task GenerateSheetByIMiniExcelDataReaderAsync(MiniExcelAsyncStreamWriter writer, IMiniExcelDataReader reader) + private async Task GenerateSheetByIMiniExcelDataReaderAsync(MiniExcelAsyncStreamWriter writer, IMiniExcelDataReader reader, CancellationToken cancellationToken) { long dimensionPlaceholderPostition = 0; await writer.WriteAsync(WorksheetXml.StartWorksheet); @@ -233,7 +233,7 @@ private async Task GenerateSheetByIMiniExcelDataReaderAsync(MiniExcelAsyncStream var props = new List(); for (var i = 0; i < reader.FieldCount; i++) { - var columnName = await reader.GetNameAsync(i); + var columnName = await reader.GetNameAsync(i, cancellationToken); if (!_configuration.DynamicColumnFirst) { @@ -280,7 +280,7 @@ private async Task GenerateSheetByIMiniExcelDataReaderAsync(MiniExcelAsyncStream } } - while (await reader.ReadAsync()) + while (await reader.ReadAsync(cancellationToken)) { await writer.WriteAsync(WorksheetXml.StartRow(yIndex)); var xIndex = 1; @@ -291,11 +291,11 @@ private async Task GenerateSheetByIMiniExcelDataReaderAsync(MiniExcelAsyncStream if (_configuration.DynamicColumnFirst) { var columnIndex = reader.GetOrdinal(props[i].Key.ToString()); - cellValue = await reader.GetValueAsync(columnIndex); + cellValue = await reader.GetValueAsync(columnIndex, cancellationToken); } else { - cellValue = await reader.GetValueAsync(i); + cellValue = await reader.GetValueAsync(i, cancellationToken); } await WriteCellAsync(writer, yIndex, xIndex, cellValue, props[i], widths); From 42cb66c47155b59b84aa04896a707311d5de1d09 Mon Sep 17 00:00:00 2001 From: izanhzh Date: Fri, 3 Jan 2025 09:39:20 +0800 Subject: [PATCH 6/9] optimization disposeAsync --- src/MiniExcel/IMiniExcelDataReader.cs | 4 ---- src/MiniExcel/MiniExcelDataReaderBase.cs | 10 ---------- 2 files changed, 14 deletions(-) diff --git a/src/MiniExcel/IMiniExcelDataReader.cs b/src/MiniExcel/IMiniExcelDataReader.cs index 1cc280d5..bc00c05a 100644 --- a/src/MiniExcel/IMiniExcelDataReader.cs +++ b/src/MiniExcel/IMiniExcelDataReader.cs @@ -28,9 +28,5 @@ public interface IMiniExcelDataReader : IDataReader, IAsyncDisposable Task ReadAsync(); Task ReadAsync(CancellationToken cancellationToken); - -#if !NET8_0_OR_GREATER - Task DisposeAsync(); -#endif } } diff --git a/src/MiniExcel/MiniExcelDataReaderBase.cs b/src/MiniExcel/MiniExcelDataReaderBase.cs index 71ab054c..194908c3 100644 --- a/src/MiniExcel/MiniExcelDataReaderBase.cs +++ b/src/MiniExcel/MiniExcelDataReaderBase.cs @@ -393,16 +393,6 @@ public virtual ValueTask DisposeAsync() Dispose(); return default; } -#else - /// - /// - /// - /// - public virtual Task DisposeAsync() - { - Dispose(); - return MiniExcelTask.CompletedTask; - } #endif /// From 07d89d378300e5e1316fa721e5cdf4bc606197dd Mon Sep 17 00:00:00 2001 From: izanhzh Date: Fri, 3 Jan 2025 11:16:29 +0800 Subject: [PATCH 7/9] optimized code --- src/MiniExcel/IMiniExcelDataReader.cs | 16 +++-------- src/MiniExcel/MiniExcelDataReaderBase.cs | 34 +++--------------------- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/src/MiniExcel/IMiniExcelDataReader.cs b/src/MiniExcel/IMiniExcelDataReader.cs index bc00c05a..3f304451 100644 --- a/src/MiniExcel/IMiniExcelDataReader.cs +++ b/src/MiniExcel/IMiniExcelDataReader.cs @@ -13,20 +13,12 @@ public interface IMiniExcelDataReader : IDataReader, IAsyncDisposable { Task CloseAsync(); - Task GetNameAsync(int i); + Task GetNameAsync(int i, CancellationToken cancellationToken = default); - Task GetNameAsync(int i, CancellationToken cancellationToken); + Task GetValueAsync(int i, CancellationToken cancellationToken = default); - Task GetValueAsync(int i); + Task NextResultAsync(CancellationToken cancellationToken = default); - Task GetValueAsync(int i, CancellationToken cancellationToken); - - Task NextResultAsync(); - - Task NextResultAsync(CancellationToken cancellationToken); - - Task ReadAsync(); - - Task ReadAsync(CancellationToken cancellationToken); + Task ReadAsync(CancellationToken cancellationToken = default); } } diff --git a/src/MiniExcel/MiniExcelDataReaderBase.cs b/src/MiniExcel/MiniExcelDataReaderBase.cs index 194908c3..402e96c0 100644 --- a/src/MiniExcel/MiniExcelDataReaderBase.cs +++ b/src/MiniExcel/MiniExcelDataReaderBase.cs @@ -204,18 +204,12 @@ public abstract class MiniExcelDataReaderBase : IMiniExcelDataReader /// public virtual bool NextResult() => false; - /// - /// - /// - /// - public Task NextResultAsync() => NextResultAsync(CancellationToken.None); - /// /// /// /// /// - public virtual Task NextResultAsync(CancellationToken cancellationToken) + public virtual Task NextResultAsync(CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -241,20 +235,13 @@ public virtual Task NextResultAsync(CancellationToken cancellationToken) /// public abstract string GetName(int i); - /// - /// - /// - /// - /// - public Task GetNameAsync(int i) => GetNameAsync(i, CancellationToken.None); - /// /// /// /// /// /// - public virtual Task GetNameAsync(int i, CancellationToken cancellationToken) + public virtual Task GetNameAsync(int i, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -280,20 +267,13 @@ public virtual Task GetNameAsync(int i, CancellationToken cancellationTo /// public abstract object GetValue(int i); - /// - /// - /// - /// - /// - public Task GetValueAsync(int i) => GetValueAsync(i, CancellationToken.None); - /// /// /// /// /// /// - public virtual Task GetValueAsync(int i, CancellationToken cancellationToken) + public virtual Task GetValueAsync(int i, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -318,18 +298,12 @@ public virtual Task GetValueAsync(int i, CancellationToken cancellationT /// public abstract bool Read(); - /// - /// - /// - /// - public Task ReadAsync() => ReadAsync(CancellationToken.None); - /// /// /// /// /// - public virtual Task ReadAsync(CancellationToken cancellationToken) + public virtual Task ReadAsync(CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { From da6c1f64ea9334918328e5ac33bd00b019b9e20a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 3 Jan 2025 12:12:55 +0800 Subject: [PATCH 8/9] chore: bump version 1.36.1 --- src/MiniExcel/MiniExcelLibs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MiniExcel/MiniExcelLibs.csproj b/src/MiniExcel/MiniExcelLibs.csproj index 12c9acf3..6cb332ce 100644 --- a/src/MiniExcel/MiniExcelLibs.csproj +++ b/src/MiniExcel/MiniExcelLibs.csproj @@ -1,7 +1,7 @@  net45;netstandard2.0;net8.0; - 1.36.0 + 1.36.1 MiniExcel From e3e0eafa08ac557bce95d75a76dcd5fc695bd0cc Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 3 Jan 2025 12:46:48 +0800 Subject: [PATCH 9/9] =?UTF-8?q?refactor:=20=E6=A0=BC=E5=BC=8F=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs | 2 +- src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs index 30faedcb..5c0b08ca 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs @@ -691,7 +691,7 @@ private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowInde { cellValue = p.CustomFormatter(cellValue); } - catch (Exception e) + catch { //ignored } diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs index 1dea68c0..f04606c5 100644 --- a/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs +++ b/src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs @@ -387,7 +387,7 @@ private void GenerateSheetByDataTable(MiniExcelStreamWriter writer, DataTable va var prop = GetColumnInfosFromDynamicConfiguration(columnName); props.Add(prop); } - + //sheet view writer.Write(GetSheetViews()); @@ -570,19 +570,19 @@ private void WriteCell(MiniExcelStreamWriter writer, int rowIndex, int cellIndex var styleIndex = tuple.Item1; // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.cell?view=openxml-3.0.1 var dataType = tuple.Item2; // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.cellvalues?view=openxml-3.0.1 var cellValue = tuple.Item3; - + if (columnInfo?.CustomFormatter != null) { try { cellValue = columnInfo.CustomFormatter(cellValue); } - catch (Exception e) + catch { //ignored } } - + var columnType = columnInfo?.ExcelColumnType ?? ColumnType.Value; /*Prefix and suffix blank space will lost after SaveAs #294*/