diff --git a/.editorconfig b/.editorconfig
index bc3e7b2e..68c52882 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -13,4 +13,18 @@ dotnet_style_qualification_for_property = false
dotnet_style_qualification_for_method = false
# IDE0065: Misplaced using directive
-csharp_using_directive_placement = outside_namespace
\ No newline at end of file
+csharp_using_directive_placement = outside_namespace
+
+# CA1835: Prefer the memory-based overloads of ReadAsync/WriteAsync methods in stream-based classes
+dotnet_diagnostic.CA1835.severity = error
+
+# CA1849: Call async methods when in an async method
+dotnet_diagnostic.CA1849.severity = error
+
+dotnet_diagnostic.CA2000.severity = error
+
+# CA2007: Do not directly await a Task
+dotnet_diagnostic.CA2007.severity = error
+
+# CA2016: Forward the CancellationToken parameter to methods that take one
+dotnet_diagnostic.CA2016.severity = error
diff --git a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj
index e986cd38..3459b9fb 100644
--- a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj
+++ b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj
@@ -7,6 +7,7 @@
enable
latest
MiniExcelLibs.Benchmarks
+ $(NoWarn);CA2000;CA2007
diff --git a/src/MiniExcel/Csv/CsvReader.cs b/src/MiniExcel/Csv/CsvReader.cs
index 39562333..dddec16d 100644
--- a/src/MiniExcel/Csv/CsvReader.cs
+++ b/src/MiniExcel/Csv/CsvReader.cs
@@ -8,10 +8,11 @@
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using System.Runtime.CompilerServices;
namespace MiniExcelLibs.Csv
{
- internal class CsvReader : IExcelReader
+ internal partial class CsvReader : IExcelReader
{
private Stream _stream;
private CsvConfiguration _config;
@@ -22,8 +23,11 @@ public CsvReader(Stream stream, IConfiguration configuration)
_config = configuration == null ? CsvConfiguration.DefaultConfiguration : (CsvConfiguration)configuration;
}
- public IEnumerable> Query(bool useHeaderRow, string sheetName, string startCell)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public async IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
if (startCell != "A1")
throw new NotImplementedException("CSV does not implement parameter startCell");
@@ -35,14 +39,22 @@ public IEnumerable> Query(bool useHeaderRow, string
var headRows = new Dictionary();
string row;
- for (var rowIndex = 1; (row = reader.ReadLine()) != null; rowIndex++)
+ for (var rowIndex = 1; (row = await reader.ReadLineAsync(
+#if NET7_0_OR_GREATER
+cancellationToken
+#endif
+ ).ConfigureAwait(false)) != null; rowIndex++)
{
string finalRow = row;
if (_config.ReadLineBreaksWithinQuotes)
{
while (finalRow.Count(c => c == '"') % 2 != 0)
{
- var nextPart = reader.ReadLine();
+ var nextPart = await reader.ReadLineAsync(
+#if NET7_0_OR_GREATER
+cancellationToken
+#endif
+ ).ConfigureAwait(false);
if (nextPart == null)
{
break;
@@ -107,62 +119,37 @@ public IEnumerable> Query(bool useHeaderRow, string
}
}
- public IEnumerable Query(string sheetName, string startCell, bool hasHeader) where T : class, new()
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new()
{
- var dynamicRecords = Query(false, sheetName, startCell);
- return ExcelOpenXmlSheetReader.QueryImpl(dynamicRecords, startCell, hasHeader, _config);
+ var dynamicRecords = QueryAsync(false, sheetName, startCell, cancellationToken);
+ return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, _config, cancellationToken);
}
- public IEnumerable> QueryRange(bool useHeaderRow, string sheetName, string startCell, string endCell)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default)
{
throw new NotImplementedException("CSV does not implement QueryRange");
}
- public IEnumerable QueryRange(string sheetName, string startCell, string endCell, bool hasHeader) where T : class, new()
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new()
{
- var dynamicRecords = QueryRange(false, sheetName, startCell, endCell);
- return ExcelOpenXmlSheetReader.QueryImpl(dynamicRecords, startCell, hasHeader, this._config);
+ var dynamicRecords = QueryRangeAsync(false, sheetName, startCell, endCell, cancellationToken);
+ return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, startCell, hasHeader, this._config, cancellationToken);
}
- public IEnumerable> QueryRange(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default)
{
throw new NotImplementedException("CSV does not implement QueryRange");
}
- public IEnumerable QueryRange(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader) where T : class, new()
- {
- var dynamicRecords = QueryRange(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex);
- return ExcelOpenXmlSheetReader.QueryImpl(dynamicRecords, ReferenceHelper.ConvertXyToCell(startRowIndex, startColumnIndex), hasHeader, this._config);
- }
-
- public Task>> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default)
- {
- return Task.Run(() => Query(useHeaderRow, sheetName, startCell), cancellationToken);
- }
-
- public async Task> QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new()
- {
- return await Task.Run(() => Query(sheetName, startCell, hasHeader), cancellationToken).ConfigureAwait(false);
- }
-
- public Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCel, CancellationToken cancellationToken = default)
- {
- return Task.Run(() => QueryRange(useHeaderRow, sheetName, startCell, endCel), cancellationToken);
- }
-
- public async Task> QueryRangeAsync(string sheetName, string startCell, string endCel, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new()
- {
- return await Task.Run(() => QueryRange(sheetName, startCell, endCel, hasHeader), cancellationToken).ConfigureAwait(false);
- }
-
- public Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default)
- {
- return Task.Run(() => QueryRange(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex), cancellationToken);
- }
-
- public async Task> QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new()
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new()
{
- return await Task.Run(() => QueryRange(sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, hasHeader), cancellationToken).ConfigureAwait(false);
+ var dynamicRecords = QueryRangeAsync(false, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken);
+ return ExcelOpenXmlSheetReader.QueryImplAsync(dynamicRecords, ReferenceHelper.ConvertXyToCell(startRowIndex, startColumnIndex), hasHeader, this._config, cancellationToken);
}
private string[] Split(string row)
diff --git a/src/MiniExcel/Csv/CsvWriter.cs b/src/MiniExcel/Csv/CsvWriter.cs
index efa46fd8..f7af71a6 100644
--- a/src/MiniExcel/Csv/CsvWriter.cs
+++ b/src/MiniExcel/Csv/CsvWriter.cs
@@ -115,22 +115,38 @@ private async Task WriteValuesAsync(StreamWriter writer, object values, str
{
writeAdapter = MiniExcelWriteAdapterFactory.GetWriteAdapter(values, _configuration);
}
- var props = writeAdapter != null ? writeAdapter.GetColumns() : await asyncWriteAdapter.GetColumnsAsync();
+ var props = writeAdapter != null ? writeAdapter.GetColumns() : await asyncWriteAdapter.GetColumnsAsync().ConfigureAwait(false);
#else
IMiniExcelWriteAdapter writeAdapter = MiniExcelWriteAdapterFactory.GetWriteAdapter(values, _configuration);
var props = writeAdapter.GetColumns();
#endif
if (props == null)
{
- await _writer.WriteAsync(_configuration.NewLine);
- await _writer.FlushAsync();
+ await _writer.WriteAsync(_configuration.NewLine
+#if NET5_0_OR_GREATER
+ .AsMemory(), cancellationToken
+#endif
+ ).ConfigureAwait(false);
+ await _writer.FlushAsync(
+#if NET8_0_OR_GREATER
+ cancellationToken
+#endif
+ ).ConfigureAwait(false);
return 0;
}
if (_printHeader)
{
- await _writer.WriteAsync(GetHeader(props));
- await _writer.WriteAsync(newLine);
+ await _writer.WriteAsync(GetHeader(props)
+#if NET5_0_OR_GREATER
+ .AsMemory(), cancellationToken
+#endif
+ ).ConfigureAwait(false);
+ await _writer.WriteAsync(newLine
+#if NET5_0_OR_GREATER
+ .AsMemory(), cancellationToken
+#endif
+ ).ConfigureAwait(false);
}
var rowBuilder = new StringBuilder();
@@ -148,8 +164,16 @@ private async Task WriteValuesAsync(StreamWriter writer, object values, str
}
RemoveTrailingSeparator(rowBuilder);
- await _writer.WriteAsync(rowBuilder.ToString());
- await _writer.WriteAsync(newLine);
+ await _writer.WriteAsync(rowBuilder.ToString()
+#if NET5_0_OR_GREATER
+ .AsMemory(), cancellationToken
+#endif
+ ).ConfigureAwait(false);
+ await _writer.WriteAsync(newLine
+#if NET5_0_OR_GREATER
+ .AsMemory(), cancellationToken
+#endif
+ ).ConfigureAwait(false);
rowsWritten++;
}
@@ -157,20 +181,28 @@ private async Task WriteValuesAsync(StreamWriter writer, object values, str
#if NETSTANDARD2_0_OR_GREATER || NET
else
{
- await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken))
+ await foreach (var row in asyncWriteAdapter.GetRowsAsync(props, cancellationToken).ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
rowBuilder.Clear();
- await foreach (var column in row)
+ await foreach (var column in row.ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
AppendColumn(rowBuilder, column);
}
RemoveTrailingSeparator(rowBuilder);
- await _writer.WriteAsync(rowBuilder.ToString());
- await _writer.WriteAsync(newLine);
+ await _writer.WriteAsync(rowBuilder.ToString()
+#if NET5_0_OR_GREATER
+ .AsMemory(), cancellationToken
+#endif
+ ).ConfigureAwait(false);
+ await _writer.WriteAsync(newLine
+#if NET5_0_OR_GREATER
+ .AsMemory(), cancellationToken
+#endif
+ ).ConfigureAwait(false);
rowsWritten++;
}
@@ -188,20 +220,32 @@ public async Task SaveAsAsync(CancellationToken cancellationToken = defau
if (_value == null)
{
- await _writer.WriteAsync("");
- await _writer.FlushAsync();
+ await _writer.WriteAsync(""
+#if NET5_0_OR_GREATER
+ .AsMemory(), cancellationToken
+#endif
+ ).ConfigureAwait(false);
+ await _writer.FlushAsync(
+#if NET8_0_OR_GREATER
+ cancellationToken
+#endif
+ ).ConfigureAwait(false);
return new int[0];
}
- var rowsWritten = await WriteValuesAsync(_writer, _value, seperator, newLine, cancellationToken);
- await _writer.FlushAsync();
+ var rowsWritten = await WriteValuesAsync(_writer, _value, seperator, newLine, cancellationToken).ConfigureAwait(false);
+ await _writer.FlushAsync(
+#if NET8_0_OR_GREATER
+ cancellationToken
+#endif
+ ).ConfigureAwait(false);
return new[] { rowsWritten };
}
public async Task InsertAsync(bool overwriteSheet = false, CancellationToken cancellationToken = default)
{
- var rowsWritten = await SaveAsAsync(cancellationToken);
+ var rowsWritten = await SaveAsAsync(cancellationToken).ConfigureAwait(false);
return rowsWritten.FirstOrDefault();
}
diff --git a/src/MiniExcel/ExcelFactory.cs b/src/MiniExcel/ExcelFactory.cs
index 36760508..a07b4d3d 100644
--- a/src/MiniExcel/ExcelFactory.cs
+++ b/src/MiniExcel/ExcelFactory.cs
@@ -5,17 +5,20 @@
using MiniExcelLibs.OpenXml.SaveByTemplate;
using System;
using System.IO;
+ using System.Threading;
+ using System.Threading.Tasks;
- internal static class ExcelReaderFactory
+ internal static partial class ExcelReaderFactory
{
- internal static IExcelReader GetProvider(Stream stream, ExcelType excelType, IConfiguration configuration)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ internal static async Task GetProviderAsync(Stream stream, ExcelType excelType, IConfiguration configuration, CancellationToken cancellationToken = default)
{
switch (excelType)
{
case ExcelType.CSV:
return new CsvReader(stream, configuration);
case ExcelType.XLSX:
- return new ExcelOpenXmlSheetReader(stream, configuration);
+ return await ExcelOpenXmlSheetReader.CreateAsync(stream, configuration, cancellationToken: cancellationToken).ConfigureAwait(false);
default:
throw new NotSupportedException("Something went wrong. Please report this issue you are experiencing with MiniExcel.");
}
diff --git a/src/MiniExcel/IExcelReader.cs b/src/MiniExcel/IExcelReader.cs
index 0581cd34..eb8e2010 100644
--- a/src/MiniExcel/IExcelReader.cs
+++ b/src/MiniExcel/IExcelReader.cs
@@ -1,23 +1,22 @@
using System;
using System.Collections.Generic;
using System.Threading;
-using System.Threading.Tasks;
namespace MiniExcelLibs
{
- internal interface IExcelReader : IDisposable
+ internal partial interface IExcelReader : IDisposable
{
- IEnumerable> Query(bool useHeaderRow, string sheetName, string startCell);
- IEnumerable Query(string sheetName, string startCell, bool hasHeader) where T : class, new();
- Task>> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default);
- Task> QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new();
- IEnumerable> QueryRange(bool useHeaderRow, string sheetName, string startCell, string endCell);
- IEnumerable QueryRange(string sheetName, string startCell, string endCell, bool hasHeader) where T : class, new();
- Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default);
- Task> QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new();
- IEnumerable> QueryRange(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex);
- IEnumerable QueryRange(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader) where T : class, new();
- Task>> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default);
- Task> QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new();
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ IAsyncEnumerable> QueryAsync(bool useHeaderRow, string sheetName, string startCell, CancellationToken cancellationToken = default);
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ IAsyncEnumerable QueryAsync(string sheetName, string startCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new();
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, string startCell, string endCell, CancellationToken cancellationToken = default);
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ IAsyncEnumerable QueryRangeAsync(string sheetName, string startCell, string endCell, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new();
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ IAsyncEnumerable> QueryRangeAsync(bool useHeaderRow, string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, CancellationToken cancellationToken = default);
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ IAsyncEnumerable QueryRangeAsync(string sheetName, int startRowIndex, int startColumnIndex, int? endRowIndex, int? endColumnIndex, bool hasHeader, CancellationToken cancellationToken = default) where T : class, new();
}
}
diff --git a/src/MiniExcel/IExcelTemplate.cs b/src/MiniExcel/IExcelTemplate.cs
index d4a66c55..6436dc46 100644
--- a/src/MiniExcel/IExcelTemplate.cs
+++ b/src/MiniExcel/IExcelTemplate.cs
@@ -3,19 +3,15 @@
namespace MiniExcelLibs
{
- internal interface IExcelTemplate
- {
- void SaveAsByTemplate(string templatePath, object value);
- void SaveAsByTemplate(byte[] templateBtyes, object value);
- void MergeSameCells(string path);
- void MergeSameCells(byte[] fileInBytes);
- }
-
- internal interface IExcelTemplateAsync : IExcelTemplate
+ internal partial interface IExcelTemplateAsync
{
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
Task SaveAsByTemplateAsync(string templatePath, object value, CancellationToken cancellationToken = default(CancellationToken));
- Task SaveAsByTemplateAsync(byte[] templateBtyes, object value, CancellationToken cancellationToken = default(CancellationToken));
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ Task SaveAsByTemplateAsync(byte[] templateBytes, object value, CancellationToken cancellationToken = default(CancellationToken));
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
Task MergeSameCellsAsync(string path, CancellationToken cancellationToken = default(CancellationToken));
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken cancellationToken = default(CancellationToken));
}
}
diff --git a/src/MiniExcel/IExcelWriter.cs b/src/MiniExcel/IExcelWriter.cs
index feea4171..74928dd2 100644
--- a/src/MiniExcel/IExcelWriter.cs
+++ b/src/MiniExcel/IExcelWriter.cs
@@ -3,11 +3,11 @@
namespace MiniExcelLibs
{
- internal interface IExcelWriter
+ internal partial interface IExcelWriter
{
- int[] SaveAs();
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
Task SaveAsAsync(CancellationToken cancellationToken = default);
- int Insert(bool overwriteSheet = false);
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
Task InsertAsync(bool overwriteSheet = false, CancellationToken cancellationToken = default);
}
}
diff --git a/src/MiniExcel/MiniExcel.Async.cs b/src/MiniExcel/MiniExcel.Async.cs
deleted file mode 100644
index 51ede3f3..00000000
--- a/src/MiniExcel/MiniExcel.Async.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-namespace MiniExcelLibs
-{
- using MiniExcelLibs.OpenXml;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Data;
- using System.IO;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- using Utils;
-
- public static partial class MiniExcel
- {
- public static async Task InsertAsync(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default)
- {
- if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
- throw new NotSupportedException("MiniExcel's Insert does not support the .xlsm format");
-
- if (!File.Exists(path))
- {
- var rowsWritten = await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, cancellationToken: cancellationToken);
- return rowsWritten.FirstOrDefault();
- }
-
- if (excelType == ExcelType.CSV)
- {
- using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan))
- return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken);
- }
- else
- {
- using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan))
- return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken);
- }
- }
-
- public static async TaskInsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default)
- {
- stream.Seek(0, SeekOrigin.End);
- // reuse code
- if (excelType == ExcelType.CSV)
- {
- var newValue = value is IEnumerable || value is IDataReader ? value : new[]{value}.AsEnumerable();
- return await ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false).InsertAsync(overwriteSheet, cancellationToken);
- }
- else
- {
- var configOrDefault = configuration ?? new OpenXmlConfiguration { FastMode = true };
- return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configOrDefault, printHeader).InsertAsync(overwriteSheet, cancellationToken);
- }
- }
-
- public static async Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false, CancellationToken cancellationToken = default)
- {
- if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
- throw new NotSupportedException("MiniExcel's SaveAs does not support the .xlsm format");
-
- using (var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew))
- return await SaveAsAsync(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, cancellationToken);
- }
-
- public static async Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAsAsync(cancellationToken);
- }
-
- public static async Task MergeSameCellsAsync(string mergedFilePath, string path, ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- await Task.Run(() => MergeSameCells(mergedFilePath, path, excelType, configuration), cancellationToken).ConfigureAwait(false);
- }
-
- public static async Task MergeSameCellsAsync(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(path, cancellationToken);
- }
-
- public static async Task MergeSameCellsAsync(this Stream stream, byte[] fileBytes, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(fileBytes, cancellationToken);
- }
-
- public static async Task> QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- return await Task.Run(() => Query(path, useHeaderRow, sheetName, excelType, startCell, configuration), cancellationToken);
- }
-
- public static async Task> QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default, bool hasHeader = true) where T : class, new()
- {
- return await ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).QueryAsync(sheetName, startCell, hasHeader, cancellationToken).ConfigureAwait(false);
- }
-
- public static async Task> QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default, bool hasHeader = true) where T : class, new()
- {
- return await Task.Run(() => Query(path, sheetName, excelType, startCell, configuration, hasHeader), cancellationToken).ConfigureAwait(false);
- }
-
- public static async Task> QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- var tcs = new TaskCompletionSource>();
- cancellationToken.Register(() =>
- {
- tcs.TrySetCanceled();
- });
-
- await Task.Run(() =>
- {
- try
- {
- tcs.TrySetResult(Query(stream, useHeaderRow, sheetName, excelType, startCell, configuration));
- }
- catch (Exception ex)
- {
- tcs.TrySetException(ex);
- }
- }, cancellationToken);
-
- return await tcs.Task;
-
- }
- public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, cancellationToken).ConfigureAwait(false);
- }
-
- public static async Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templateBytes, value, cancellationToken).ConfigureAwait(false);
- }
-
- public static async Task SaveAsByTemplateAsync(string path, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- await Task.Run(() => SaveAsByTemplate(path, templatePath, value, configuration), cancellationToken).ConfigureAwait(false);
- }
-
- public static async Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- await Task.Run(() => SaveAsByTemplate(path, templateBytes, value, configuration), cancellationToken).ConfigureAwait(false);
- }
-
- ///
- /// QueryAsDataTable is not recommended, because it'll load all data into memory.
- ///
- [Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")]
- public static async Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- return await Task.Run(() => QueryAsDataTable(path, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration), cancellationToken).ConfigureAwait(false);
- }
-
- ///
- /// QueryAsDataTable is not recommended, because it'll load all data into memory.
- ///
- [Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")]
- public static async Task QueryAsDataTableAsync(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default)
- {
- return await Task.Run(() => QueryAsDataTable(stream, useHeaderRow, sheetName, excelType, startCell, configuration), cancellationToken).ConfigureAwait(false);
- }
- }
-}
diff --git a/src/MiniExcel/MiniExcel.cs b/src/MiniExcel/MiniExcel.cs
index 03470dbd..047f9010 100644
--- a/src/MiniExcel/MiniExcel.cs
+++ b/src/MiniExcel/MiniExcel.cs
@@ -10,20 +10,25 @@
using System.Dynamic;
using System.IO;
using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
namespace MiniExcelLibs
{
public static partial class MiniExcel
{
- public static void AddPicture(string path, params MiniExcelPicture[] images)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task AddPictureAsync(string path, CancellationToken cancellationToken = default, params MiniExcelPicture[] images)
{
using (var stream = File.Open(path, FileMode.OpenOrCreate))
- MiniExcelPictureImplement.AddPicture(stream, images);
+ await MiniExcelPictureImplement.AddPictureAsync(stream, cancellationToken, images).ConfigureAwait(false);
}
- public static void AddPicture(Stream excelStream, params MiniExcelPicture[] images)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task AddPicture(Stream excelStream, CancellationToken cancellationToken = default, params MiniExcelPicture[] images)
{
- MiniExcelPictureImplement.AddPicture(excelStream, images);
+ await MiniExcelPictureImplement.AddPictureAsync(excelStream, cancellationToken, images).ConfigureAwait(false);
}
public static MiniExcelDataReader GetReader(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
@@ -37,83 +42,94 @@ public static MiniExcelDataReader GetReader(this Stream stream, bool useHeaderRo
return new MiniExcelDataReader(stream, useHeaderRow, sheetName, excelType, startCell, configuration);
}
- public static int Insert(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task InsertAsync(string path, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default)
{
if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
throw new NotSupportedException("MiniExcel's Insert does not support the .xlsm format");
if (!File.Exists(path))
{
- var rowsWritten = SaveAs(path, value, printHeader, sheetName, excelType, configuration);
+ var rowsWritten = await SaveAsAsync(path, value, printHeader, sheetName, excelType, configuration, cancellationToken: cancellationToken).ConfigureAwait(false);
return rowsWritten.FirstOrDefault();
}
if (excelType == ExcelType.CSV)
{
using (var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan))
- return Insert(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet);
+ return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken).ConfigureAwait(false);
}
else
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan))
- return Insert(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet);
+ return await InsertAsync(stream, value, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, printHeader, overwriteSheet, cancellationToken).ConfigureAwait(false);
}
}
- public static int Insert(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "TODO: CsvWriter needs to be disposed")]
+ public static async Task InsertAsync(this Stream stream, object value, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, bool printHeader = true, bool overwriteSheet = false, CancellationToken cancellationToken = default)
{
stream.Seek(0, SeekOrigin.End);
if (excelType == ExcelType.CSV)
{
var newValue = value is IEnumerable || value is IDataReader ? value : new[] { value };
- return ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false).Insert(overwriteSheet);
+ var provider = ExcelWriterFactory.GetProvider(stream, newValue, sheetName, excelType, configuration, false);
+ return await provider.InsertAsync(overwriteSheet, cancellationToken).ConfigureAwait(false);
}
else
{
var configOrDefault = configuration ?? new OpenXmlConfiguration { FastMode = true };
- return ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configOrDefault, printHeader).Insert(overwriteSheet);
+ return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configOrDefault, printHeader).InsertAsync(overwriteSheet, cancellationToken).ConfigureAwait(false);
}
}
- public static int[] SaveAs(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null, bool overwriteFile = false, CancellationToken cancellationToken = default)
{
if (Path.GetExtension(path).ToLowerInvariant() == ".xlsm")
throw new NotSupportedException("MiniExcel's SaveAs does not support the .xlsm format");
using (var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew))
- return SaveAs(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration);
+ return await SaveAsAsync(stream, value, printHeader, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), configuration, cancellationToken).ConfigureAwait(false);
}
- public static int[] SaveAs(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "TODO: CsvWriter needs to be disposed")]
+ public static async Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
- return ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAs();
+ return await ExcelWriterFactory.GetProvider(stream, value, sheetName, excelType, configuration, printHeader).SaveAsAsync(cancellationToken).ConfigureAwait(false);
}
- public static IEnumerable Query(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true) where T : class, new()
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async IAsyncEnumerable QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new()
{
using (var stream = FileHelper.OpenSharedRead(path))
- foreach (var item in Query(stream, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, hasHeader))
+ await foreach (var item in QueryAsync(stream, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, hasHeader, cancellationToken).ConfigureAwait(false))
yield return item; //Foreach yield return twice reason : https://stackoverflow.com/questions/66791982/ienumerable-extract-code-lazy-loading-show-stream-was-not-readable
}
- public static IEnumerable Query(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true) where T : class, new()
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async IAsyncEnumerable QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, bool hasHeader = true, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new()
{
- using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration))
- foreach (var item in excelReader.Query(sheetName, startCell, hasHeader))
+ using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false))
+ await foreach (var item in excelReader.QueryAsync(sheetName, startCell, hasHeader, cancellationToken).ConfigureAwait(false))
yield return item;
}
-
- public static IEnumerable Query(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
+
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async IAsyncEnumerable QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
using (var stream = FileHelper.OpenSharedRead(path))
- foreach (var item in Query(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration))
+ await foreach (var item in QueryAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, cancellationToken).ConfigureAwait(false))
yield return item;
}
-
- public static IEnumerable Query(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
+
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async IAsyncEnumerable QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
- using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration))
- foreach (var item in excelReader.Query(useHeaderRow, sheetName, startCell))
+ using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false))
+ await foreach (var item in excelReader.QueryAsync(useHeaderRow, sheetName, startCell, cancellationToken).ConfigureAwait(false))
yield return item.Aggregate(new ExpandoObject() as IDictionary,
(dict, p) => { dict.Add(p); return dict; });
}
@@ -135,76 +151,87 @@ public static IEnumerable Query(this Stream stream, bool useHeaderRow =
/// lower right corner
///
///
- public static IEnumerable QueryRange(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
using (var stream = FileHelper.OpenSharedRead(path))
- foreach (var item in QueryRange(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, endCell, configuration))
+ await foreach (var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startCell, endCell, configuration, cancellationToken).ConfigureAwait(false))
yield return item;
}
- public static IEnumerable QueryRange(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async IAsyncEnumerable QueryRangeAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", string endCell = "", IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
- using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration))
- foreach (var item in excelReader.QueryRange(useHeaderRow, sheetName, startCell, endCell))
+ using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false))
+ await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startCell, endCell, cancellationToken).ConfigureAwait(false))
yield return item.Aggregate(new ExpandoObject() as IDictionary,
(dict, p) => { dict.Add(p); return dict; });
}
- public static IEnumerable QueryRange(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async IAsyncEnumerable QueryRangeAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
using (var stream = FileHelper.OpenSharedRead(path))
- foreach (var item in QueryRange(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration))
+ await foreach (var item in QueryRangeAsync(stream, useHeaderRow, sheetName, ExcelTypeHelper.GetExcelType(path, excelType), startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration, cancellationToken).ConfigureAwait(false))
yield return item;
}
-
- public static IEnumerable QueryRange(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null)
+
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async IAsyncEnumerable QueryRangeAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, int startRowIndex = 1, int startColumnIndex = 1, int? endRowIndex = null, int? endColumnIndex = null, IConfiguration configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
- using (var excelReader = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration))
- foreach (var item in excelReader.QueryRange(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex))
+ using (var excelReader = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false))
+ await foreach (var item in excelReader.QueryRangeAsync(useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, cancellationToken).ConfigureAwait(false))
yield return item.Aggregate(new ExpandoObject() as IDictionary,
(dict, p) => { dict.Add(p); return dict; });
}
#endregion QueryRange
- public static void SaveAsByTemplate(string path, string templatePath, object value, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task SaveAsByTemplateAsync(string path, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
using (var stream = File.Create(path))
- SaveAsByTemplate(stream, templatePath, value, configuration);
+ await SaveAsByTemplateAsync(stream, templatePath, value, configuration, cancellationToken).ConfigureAwait(false);
}
- public static void SaveAsByTemplate(string path, byte[] templateBytes, object value, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
using (var stream = File.Create(path))
- SaveAsByTemplate(stream, templateBytes, value, configuration);
+ await SaveAsByTemplateAsync(stream, templateBytes, value, configuration, cancellationToken).ConfigureAwait(false);
}
- public static void SaveAsByTemplate(this Stream stream, string templatePath, object value, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
- ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplate(templatePath, value);
+ await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templatePath, value, cancellationToken).ConfigureAwait(false);
}
- public static void SaveAsByTemplate(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value, IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
- ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplate(templateBytes, value);
+ await ExcelTemplateFactory.GetProvider(stream, configuration).SaveAsByTemplateAsync(templateBytes, value, cancellationToken).ConfigureAwait(false);
}
#region MergeCells
- public static void MergeSameCells(string mergedFilePath, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task MergeSameCellsAsync(string mergedFilePath, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
using (var stream = File.Create(mergedFilePath))
- MergeSameCells(stream, path, excelType, configuration);
+ await MergeSameCellsAsync(stream, path, excelType, configuration, cancellationToken).ConfigureAwait(false);
}
- public static void MergeSameCells(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task MergeSameCellsAsync(this Stream stream, string path, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
- ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCells(path);
+ await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(path, cancellationToken).ConfigureAwait(false);
}
- public static void MergeSameCells(this Stream stream, byte[] filePath, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task MergeSameCellsAsync(this Stream stream, byte[] filePath, ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
- ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCells(filePath);
+ await ExcelTemplateFactory.GetProvider(stream, configuration, excelType).MergeSameCellsAsync(filePath, cancellationToken).ConfigureAwait(false);
}
#endregion
@@ -213,25 +240,30 @@ public static void MergeSameCells(this Stream stream, byte[] filePath, ExcelType
/// QueryAsDataTable is not recommended, because it'll load all data into memory.
///
[Obsolete("QueryAsDataTable is not recommended, because it'll load all data into memory.")]
- public static DataTable QueryAsDataTable(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public async static Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
using (var stream = FileHelper.OpenSharedRead(path))
{
- return QueryAsDataTable(stream, useHeaderRow, sheetName, excelType: ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration);
+ return await QueryAsDataTableAsync(stream, useHeaderRow, sheetName, excelType: ExcelTypeHelper.GetExcelType(path, excelType), startCell, configuration, cancellationToken).ConfigureAwait(false);
}
}
- public static DataTable QueryAsDataTable(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public async static Task QueryAsDataTableAsync(this Stream stream, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/
- sheetName = stream.GetSheetNames(configuration as OpenXmlConfiguration).First();
+ sheetName = (await stream.GetSheetNamesAsync(configuration as OpenXmlConfiguration, cancellationToken).ConfigureAwait(false)).First();
var dt = new DataTable(sheetName);
var first = true;
- var rows = ExcelReaderFactory.GetProvider(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration).Query(false, sheetName, startCell);
+ var provider = await ExcelReaderFactory.GetProviderAsync(stream, ExcelTypeHelper.GetExcelType(stream, excelType), configuration, cancellationToken).ConfigureAwait(false);
+ var rows = provider.QueryAsync(false, sheetName, startCell, cancellationToken).ConfigureAwait(false);
var columnDict = new Dictionary();
- foreach (IDictionary row in rows)
+ await foreach (IDictionary row in rows.WithCancellation(cancellationToken).ConfigureAwait(false))
{
if (first)
{
@@ -266,82 +298,110 @@ public static DataTable QueryAsDataTable(this Stream stream, bool useHeaderRow =
return dt;
}
- public static List GetSheetNames(string path, OpenXmlConfiguration config = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task> GetSheetNamesAsync(string path, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default)
{
using (var stream = FileHelper.OpenSharedRead(path))
- return GetSheetNames(stream, config);
+ return await GetSheetNamesAsync(stream, config, cancellationToken).ConfigureAwait(false);
}
- public static List GetSheetNames(this Stream stream, OpenXmlConfiguration config = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task> GetSheetNamesAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default)
{
config = config ?? OpenXmlConfiguration.DefaultConfig;
+ // For some reason this breaks the tests
+#pragma warning disable CA2000 // Dispose objects before losing scope
var archive = new ExcelOpenXmlZip(stream);
- return new ExcelOpenXmlSheetReader(stream, config).GetWorkbookRels(archive.entries).Select(s => s.Name).ToList();
+#pragma warning restore CA2000 // Dispose objects before losing scope
+ using var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, config, cancellationToken: cancellationToken).ConfigureAwait(false);
+ var rels = await reader.GetWorkbookRelsAsync(archive.entries, cancellationToken).ConfigureAwait(false);
+ return rels.Select(s => s.Name).ToList();
}
- public static List GetSheetInformations(string path, OpenXmlConfiguration config = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task> GetSheetInformationsAsync(string path, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default)
{
using (var stream = FileHelper.OpenSharedRead(path))
- return GetSheetInformations(stream, config);
+ return await GetSheetInformationsAsync(stream, config, cancellationToken).ConfigureAwait(false);
}
- public static List GetSheetInformations(this Stream stream, OpenXmlConfiguration config = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task> GetSheetInformationsAsync(this Stream stream, OpenXmlConfiguration config = null, CancellationToken cancellationToken = default)
{
config = config ?? OpenXmlConfiguration.DefaultConfig;
- var archive = new ExcelOpenXmlZip(stream);
- return new ExcelOpenXmlSheetReader(stream, config).GetWorkbookRels(archive.entries).Select((s, i) => s.ToSheetInfo((uint)i)).ToList();
+ using var archive = new ExcelOpenXmlZip(stream);
+ using var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, config, cancellationToken: cancellationToken).ConfigureAwait(false);
+ var rels = await reader.GetWorkbookRelsAsync(archive.entries, cancellationToken).ConfigureAwait(false);
+ return rels.Select((s, i) => s.ToSheetInfo((uint)i)).ToList();
}
- public static ICollection GetColumns(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task> GetColumnsAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
using (var stream = FileHelper.OpenSharedRead(path))
- return GetColumns(stream, useHeaderRow, sheetName, excelType, startCell, configuration);
+ return await GetColumnsAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration, cancellationToken).ConfigureAwait(false);
}
- public static ICollection GetColumns(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task> GetColumnsAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null, CancellationToken cancellationToken = default)
{
- return (Query(stream, useHeaderRow, sheetName, excelType, startCell, configuration).FirstOrDefault() as IDictionary)?.Keys;
+#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
+ await using var enumerator = QueryAsync(stream, useHeaderRow, sheetName, excelType, startCell, configuration, cancellationToken).GetAsyncEnumerator(cancellationToken);
+#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
+ _ = enumerator.ConfigureAwait(false);
+ if (!await enumerator.MoveNextAsync().ConfigureAwait(false))
+ {
+ return null;
+ }
+ return (enumerator.Current as IDictionary)?.Keys;
}
- public static IList GetSheetDimensions(string path)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task> GetSheetDimensionsAsync(string path, CancellationToken cancellationToken = default)
{
using (var stream = FileHelper.OpenSharedRead(path))
- return GetSheetDimensions(stream);
+ return await GetSheetDimensionsAsync(stream, cancellationToken).ConfigureAwait(false);
}
- public static IList GetSheetDimensions(this Stream stream)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task> GetSheetDimensionsAsync(this Stream stream, CancellationToken cancellationToken = default)
{
- return new ExcelOpenXmlSheetReader(stream, null).GetDimensions();
+ using var reader = await ExcelOpenXmlSheetReader.CreateAsync(stream, null, cancellationToken: cancellationToken).ConfigureAwait(false);
+ return await reader.GetDimensionsAsync(cancellationToken).ConfigureAwait(false);
}
- public static void ConvertCsvToXlsx(string csv, string xlsx)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task ConvertCsvToXlsxAsync(string csv, string xlsx, CancellationToken cancellationToken = default)
{
using (var csvStream = FileHelper.OpenSharedRead(csv))
using (var xlsxStream = new FileStream(xlsx, FileMode.CreateNew))
{
- ConvertCsvToXlsx(csvStream, xlsxStream);
+ await ConvertCsvToXlsxAsync(csvStream, xlsxStream, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
- public static void ConvertCsvToXlsx(Stream csv, Stream xlsx)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task ConvertCsvToXlsxAsync(Stream csv, Stream xlsx, CancellationToken cancellationToken = default)
{
- var value = Query(csv, useHeaderRow: false, excelType: ExcelType.CSV);
- SaveAs(xlsx, value, printHeader: false, excelType: ExcelType.XLSX);
+ var value = QueryAsync(csv, useHeaderRow: false, excelType: ExcelType.CSV, cancellationToken: cancellationToken);
+ await SaveAsAsync(xlsx, value, printHeader: false, excelType: ExcelType.XLSX, cancellationToken: cancellationToken).ConfigureAwait(false);
}
- public static void ConvertXlsxToCsv(string xlsx, string csv)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task ConvertXlsxToCsvAsync(string xlsx, string csv, CancellationToken cancellationToken = default)
{
using (var xlsxStream = FileHelper.OpenSharedRead(xlsx))
using (var csvStream = new FileStream(csv, FileMode.CreateNew))
- ConvertXlsxToCsv(xlsxStream, csvStream);
+ await ConvertXlsxToCsvAsync(xlsxStream, csvStream, cancellationToken).ConfigureAwait(false);
}
- public static void ConvertXlsxToCsv(Stream xlsx, Stream csv)
+ [Zomp.SyncMethodGenerator.CreateSyncVersion]
+ public static async Task ConvertXlsxToCsvAsync(Stream xlsx, Stream csv, CancellationToken cancellationToken = default)
{
- var value = Query(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX);
- SaveAs(csv, value, printHeader: false, excelType: ExcelType.CSV);
+ var value = QueryAsync(xlsx, useHeaderRow: false, excelType: ExcelType.XLSX, cancellationToken: cancellationToken);
+ await SaveAsAsync(csv, value, printHeader: false, excelType: ExcelType.CSV, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
}
\ No newline at end of file
diff --git a/src/MiniExcel/MiniExcelLibs.csproj b/src/MiniExcel/MiniExcelLibs.csproj
index eb4a83c6..f40c18ac 100644
--- a/src/MiniExcel/MiniExcelLibs.csproj
+++ b/src/MiniExcel/MiniExcelLibs.csproj
@@ -1,9 +1,9 @@
- net45;netstandard2.0;net8.0;net9.0
+ net462;netstandard2.0;net8.0;net9.0
1.41.2
-
+
8
@@ -38,7 +38,7 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=trueREADME.md
-
+
@@ -52,7 +52,10 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true
-
+
+
+
+
diff --git a/src/MiniExcel/MiniExcelTask.cs b/src/MiniExcel/MiniExcelTask.cs
index 06f8d414..2a3fb7b0 100644
--- a/src/MiniExcel/MiniExcelTask.cs
+++ b/src/MiniExcel/MiniExcelTask.cs
@@ -6,7 +6,7 @@ namespace MiniExcelLibs
{
internal class MiniExcelTask
{
-#if NET45
+#if NET462
public static Task CompletedTask = Task.FromResult(0);
#else
public static Task CompletedTask = Task.CompletedTask;
@@ -14,7 +14,7 @@ internal class MiniExcelTask
public static Task FromException(Exception exception)
{
-#if NET45
+#if NET462
var tcs = new TaskCompletionSource