diff --git a/src/MiniExcel.Core/Helpers/ExpandoHelper.cs b/src/MiniExcel.Core/Helpers/ExpandoHelper.cs index 5d5572ef..e099a010 100644 --- a/src/MiniExcel.Core/Helpers/ExpandoHelper.cs +++ b/src/MiniExcel.Core/Helpers/ExpandoHelper.cs @@ -10,12 +10,7 @@ public static class ExpandoHelper for (int i = startCellIndex; i <= maxColumnIndex; i++) { var key = CellReferenceConverter.GetAlphabeticalIndex(i); -#if NETCOREAPP2_0_OR_GREATER cell.TryAdd(key, null); -#else - if (!cell.ContainsKey(key)) - cell.Add(key, null); -#endif } return cell; @@ -26,12 +21,7 @@ public static class ExpandoHelper IDictionary cell = new ExpandoObject(); foreach (var hr in headers) { -#if NETCOREAPP2_0_OR_GREATER cell.TryAdd(hr.Value, null); -#else - if (!cell.ContainsKey(hr.Value)) - cell.Add(hr.Value, null); -#endif } return cell; diff --git a/src/MiniExcel.Core/Helpers/MiniExcelStreamWriter.cs b/src/MiniExcel.Core/Helpers/MiniExcelStreamWriter.cs index 03ce8479..aa0711ed 100644 --- a/src/MiniExcel.Core/Helpers/MiniExcelStreamWriter.cs +++ b/src/MiniExcel.Core/Helpers/MiniExcelStreamWriter.cs @@ -12,13 +12,12 @@ public async Task WriteAsync(string content, CancellationToken cancellationToken { if (!string.IsNullOrEmpty(content)) { -#if NET8_0_OR_GREATER - await _streamWriter.WriteAsync(content.AsMemory(), cancellationToken) +#if NET + await _streamWriter.WriteAsync(content.AsMemory(), cancellationToken).ConfigureAwait(false); #else cancellationToken.ThrowIfCancellationRequested(); - await _streamWriter.WriteAsync(content) + await _streamWriter.WriteAsync(content).ConfigureAwait(false); #endif - .ConfigureAwait(false); } } @@ -33,7 +32,7 @@ public async Task WriteAndFlushAsync(string content, CancellationToken can public async Task FlushAndGetPositionAsync(CancellationToken cancellationToken = default) { await _streamWriter.FlushAsync( -#if NET8_0_OR_GREATER +#if NET cancellationToken #endif ).ConfigureAwait(false); diff --git a/src/MiniExcel.Core/Helpers/Polyfills.cs b/src/MiniExcel.Core/Helpers/Polyfills.cs index 164d0792..47ad6be6 100644 --- a/src/MiniExcel.Core/Helpers/Polyfills.cs +++ b/src/MiniExcel.Core/Helpers/Polyfills.cs @@ -1,5 +1,7 @@ using System.ComponentModel; using System.IO.Compression; +using System.Runtime.InteropServices; +using System.Xml.Linq; namespace MiniExcelLib.Core.Helpers; @@ -9,10 +11,23 @@ in the other projects that require it so as to prevent the consumers' IDEs to be public static class Polyfills { #if NETSTANDARD2_0 - [EditorBrowsable(EditorBrowsableState.Advanced)] - public static TValue? GetValueOrDefault(this IDictionary dictionary, TKey key, TValue? defaultValue = default) + extension(IDictionary dictionary) { - return dictionary.TryGetValue(key, out var value) ? value : defaultValue; + [EditorBrowsable(EditorBrowsableState.Advanced)] + public TValue? GetValueOrDefault(TKey key, TValue? defaultValue = default) + { + return dictionary.TryGetValue(key, out var value) ? value : defaultValue; + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + public bool TryAdd(TKey key, TValue value) + { + if (dictionary.ContainsKey(key)) + return false; + + dictionary.Add(key, value); + return true; + } } [EditorBrowsable(EditorBrowsableState.Advanced)] @@ -45,6 +60,50 @@ public static IEnumerable ExceptBy(this IEnumerable new(stream, continueOnCapturedContext); + } + + /// + /// This is a copy of the runtime's , which we cannot instantiate directly for our needs + /// due to the constructor that initializes the object to eventually dispose being internal. + /// + [StructLayout(LayoutKind.Auto)] + [EditorBrowsable(EditorBrowsableState.Advanced)] + public readonly struct StreamConfiguredAsyncDisposable : IDisposable + { + private readonly Stream? _source; + private readonly bool _continueOnCapturedContext; + + internal StreamConfiguredAsyncDisposable(Stream? source, bool continueOnCapturedContext) + { + _source = source; + _continueOnCapturedContext = continueOnCapturedContext; + } + + public ConfiguredValueTaskAwaitable DisposeAsync() + { + return _source is not null + ? _source.DisposeAsync().ConfigureAwait(_continueOnCapturedContext) + : default; + } + + public void Dispose() => _source?.Dispose(); + } #endif #if !NET10_0_OR_GREATER @@ -58,6 +117,22 @@ public ValueTask OpenAsync(CancellationToken cancellationToken = default } } + extension(XDocument doc) + { + [EditorBrowsable(EditorBrowsableState.Advanced)] + public static ValueTask LoadAsync(Stream stream, LoadOptions loadOptions, CancellationToken cancellationToken = default) + { + return new ValueTask(XDocument.Load(stream, loadOptions)); + } + + [EditorBrowsable(EditorBrowsableState.Advanced)] + public ValueTask SaveAsync(Stream stream, SaveOptions saveOptions, CancellationToken cancellationToken = default) + { + doc.Save(stream, saveOptions); + return default; + } + } + extension(ZipArchive) { [EditorBrowsable(EditorBrowsableState.Advanced)] diff --git a/src/MiniExcel.Core/MiniExcelDataReader.cs b/src/MiniExcel.Core/MiniExcelDataReader.cs index 6f34a85b..f7f2d77d 100644 --- a/src/MiniExcel.Core/MiniExcelDataReader.cs +++ b/src/MiniExcel.Core/MiniExcelDataReader.cs @@ -294,17 +294,11 @@ public async Task CloseAsync() if (IsClosed) return; - if (_isAsyncSource) - { + if (_isAsyncSource) await _asyncSource!.DisposeAsync().ConfigureAwait(false); - } - _source?.Dispose(); -#if NETCOREAPP3_0_OR_GREATER + _source?.Dispose(); await _stream!.DisposeAsync().ConfigureAwait(false); -#else - _stream.Dispose(); -#endif IsClosed = true; } diff --git a/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs b/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs index 257509f5..fb82fc7d 100644 --- a/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs +++ b/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs @@ -145,8 +145,8 @@ public static partial class MiniExcelMapper else throw new InvalidCastException($"{vs} cannot be cast to DateTime"); } - -#if NET6_0_OR_GREATER + +#if NET else if (map.ExcludeNullableType == typeof(DateOnly)) { if (itemValue is DateOnly) diff --git a/src/MiniExcel.Csv/Api/CsvExporter.cs b/src/MiniExcel.Csv/Api/CsvExporter.cs index e9ac9039..3da4a5ee 100644 --- a/src/MiniExcel.Csv/Api/CsvExporter.cs +++ b/src/MiniExcel.Csv/Api/CsvExporter.cs @@ -1,5 +1,3 @@ -using MiniExcelLib.Core; - // ReSharper disable once CheckNamespace namespace MiniExcelLib.Csv; @@ -20,7 +18,9 @@ public async Task AppendAsync(string path, object value, bool printHeader = return rowsWritten.FirstOrDefault(); } - using var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan); + var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read, 4096, FileOptions.SequentialScan); + await using var disposableStream = stream.ConfigureAwait(false); + return await AppendAsync(stream, value, configuration, progress, cancellationToken).ConfigureAwait(false); } @@ -39,7 +39,9 @@ public async Task AppendAsync(Stream stream, object value, CsvConfiguration public async Task ExportAsync(string path, object value, bool printHeader = true, bool overwriteFile = false, CsvConfiguration? configuration = null, IProgress? progress = null, CancellationToken cancellationToken = default) { - using var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew); + var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew); + await using var disposableStream = stream.ConfigureAwait(false); + return await ExportAsync(stream, value, printHeader, configuration, progress, cancellationToken).ConfigureAwait(false); } diff --git a/src/MiniExcel.Csv/Api/CsvImporter.cs b/src/MiniExcel.Csv/Api/CsvImporter.cs index 9bbbfb08..8d10290c 100644 --- a/src/MiniExcel.Csv/Api/CsvImporter.cs +++ b/src/MiniExcel.Csv/Api/CsvImporter.cs @@ -15,7 +15,8 @@ public async IAsyncEnumerable QueryAsync(string path, bool treatHeaderAsDa CsvConfiguration? configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new() { - using var stream = FileHelper.OpenSharedRead(path); + var stream = FileHelper.OpenSharedRead(path); + await using var disposableStream = stream.ConfigureAwait(false); var query = QueryAsync(stream, treatHeaderAsData, configuration, cancellationToken); @@ -38,7 +39,9 @@ public async IAsyncEnumerable QueryAsync(Stream stream, bool treatHeaderAs public async IAsyncEnumerable QueryAsync(string path, bool useHeaderRow = false, CsvConfiguration? configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { - using var stream = FileHelper.OpenSharedRead(path); + var stream = FileHelper.OpenSharedRead(path); + await using var disposableStream = stream.ConfigureAwait(false); + await foreach (var item in QueryAsync(stream, useHeaderRow, configuration, cancellationToken).ConfigureAwait(false)) yield return item; } @@ -64,7 +67,9 @@ public async IAsyncEnumerable QueryAsync(Stream stream, bool useHeaderR public async Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, CsvConfiguration? configuration = null, CancellationToken cancellationToken = default) { - using var stream = FileHelper.OpenSharedRead(path); + var stream = FileHelper.OpenSharedRead(path); + await using var disposableStream = stream.ConfigureAwait(false); + return await QueryAsDataTableAsync(stream, useHeaderRow, configuration, cancellationToken).ConfigureAwait(false); } @@ -127,7 +132,8 @@ public async Task QueryAsDataTableAsync(Stream stream, bool useHeader public async Task> GetColumnNamesAsync(string path, bool useHeaderRow = false, CsvConfiguration? configuration = null, CancellationToken cancellationToken = default) { - using var stream = FileHelper.OpenSharedRead(path); + var stream = FileHelper.OpenSharedRead(path); + await using var disposableStream = stream.ConfigureAwait(false); return await GetColumnNamesAsync(stream, useHeaderRow, configuration, cancellationToken).ConfigureAwait(false); } diff --git a/src/MiniExcel.Csv/CsvReader.cs b/src/MiniExcel.Csv/CsvReader.cs index 0b01092d..f28e2f1c 100644 --- a/src/MiniExcel.Csv/CsvReader.cs +++ b/src/MiniExcel.Csv/CsvReader.cs @@ -33,7 +33,7 @@ internal CsvReader(Stream stream, IMiniExcelConfiguration? configuration) var rowIndex = 0; while (await reader.ReadLineAsync( -#if NET7_0_OR_GREATER +#if NET cancellationToken #endif ).ConfigureAwait(false) is { } row) @@ -49,7 +49,7 @@ internal CsvReader(Stream stream, IMiniExcelConfiguration? configuration) while (finalRow.Count(c => c == '"') % 2 != 0) { var nextPart = await reader.ReadLineAsync( -#if NET7_0_OR_GREATER +#if NET cancellationToken #endif ).ConfigureAwait(false); @@ -159,12 +159,19 @@ private string[] Split(string row) //this code from S.O : https://stackoverflow.com/a/11365961/9131476 return Regex.Split(row, $"[\t{_config.Seperator}](?=(?:[^\"]|\"[^\"]*\")*$)") - .Select(s => Regex.Replace(s.Replace("\"\"", "\""), "^\"|\"$", "")) + .Select(s => DoubleQuotesRegexImpl.Replace(s.Replace("\"\"", "\""), "")) .ToArray(); } public void Dispose() { - ((Stream?)_stream)?.Dispose(); + _stream?.Dispose(); } +#if NET + [GeneratedRegex("^\"|\"$")] + private static partial Regex DoubleQuotesRegex(); + private static readonly Regex DoubleQuotesRegexImpl = DoubleQuotesRegex(); +#else + private static readonly Regex DoubleQuotesRegexImpl = new Regex("^\"|\"$", RegexOptions.Compiled); +#endif } diff --git a/src/MiniExcel.Csv/CsvWriter.cs b/src/MiniExcel.Csv/CsvWriter.cs index cc24173e..506f9801 100644 --- a/src/MiniExcel.Csv/CsvWriter.cs +++ b/src/MiniExcel.Csv/CsvWriter.cs @@ -60,31 +60,26 @@ private async Task WriteValuesAsync(StreamWriter writer, object values, str if (mappings is null) { - await _writer.WriteAsync(_configuration.NewLine -#if NET5_0_OR_GREATER - .AsMemory(), cancellationToken -#endif - ).ConfigureAwait(false); - await _writer.FlushAsync( -#if NET8_0_OR_GREATER - cancellationToken +#if NET + await _writer.WriteAsync(_configuration.NewLine.AsMemory(), cancellationToken).ConfigureAwait(false); + await _writer.FlushAsync(cancellationToken).ConfigureAwait(false); +#else + await _writer.WriteAsync(_configuration.NewLine).ConfigureAwait(false); + await _writer.FlushAsync().ConfigureAwait(false); #endif - ).ConfigureAwait(false); + return 0; } if (_printHeader) { - await _writer.WriteAsync(GetHeader(mappings) -#if NET5_0_OR_GREATER - .AsMemory(), cancellationToken -#endif - ).ConfigureAwait(false); - await _writer.WriteAsync(newLine -#if NET5_0_OR_GREATER - .AsMemory(), cancellationToken +#if NET + await _writer.WriteAsync(GetHeader(mappings).AsMemory(), cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(newLine.AsMemory(), cancellationToken).ConfigureAwait(false); +#else + await _writer.WriteAsync(GetHeader(mappings)).ConfigureAwait(false); + await _writer.WriteAsync(newLine).ConfigureAwait(false); #endif - ).ConfigureAwait(false); } var rowBuilder = new StringBuilder(); @@ -103,17 +98,13 @@ await _writer.WriteAsync(newLine } RemoveTrailingSeparator(rowBuilder); - 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 +#if NET + await _writer.WriteAsync(rowBuilder.ToString().AsMemory(), cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(newLine.AsMemory(), cancellationToken).ConfigureAwait(false); +#else + await _writer.WriteAsync(rowBuilder.ToString()).ConfigureAwait(false); + await _writer.WriteAsync(newLine).ConfigureAwait(false); #endif - ).ConfigureAwait(false); - rowsWritten++; } } @@ -132,17 +123,13 @@ await _writer.WriteAsync(newLine } RemoveTrailingSeparator(rowBuilder); - 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 +#if NET + await _writer.WriteAsync(rowBuilder.ToString().AsMemory(), cancellationToken).ConfigureAwait(false); + await _writer.WriteAsync(newLine.AsMemory(), cancellationToken).ConfigureAwait(false); +#else + await _writer.WriteAsync(rowBuilder.ToString()).ConfigureAwait(false); + await _writer.WriteAsync(newLine).ConfigureAwait(false); #endif - ).ConfigureAwait(false); - rowsWritten++; } #endif @@ -152,10 +139,8 @@ await _writer.WriteAsync(newLine finally { #if !SYNC_ONLY - if (asyncWriteAdapter is IAsyncDisposable asyncDisposable) - { - await asyncDisposable.DisposeAsync().ConfigureAwait(false); - } + if (asyncWriteAdapter is not null) + await asyncWriteAdapter.DisposeAsync().ConfigureAwait(false); #endif } } @@ -170,22 +155,19 @@ public async Task SaveAsAsync(IProgress? progress = null, Cancellati if (_value is null) { - await _writer.WriteAsync("" -#if NET5_0_OR_GREATER - .AsMemory(), cancellationToken -#endif - ).ConfigureAwait(false); - await _writer.FlushAsync( -#if NET5_0_OR_GREATER - cancellationToken +#if NET + await _writer.WriteAsync("".AsMemory(), cancellationToken).ConfigureAwait(false); + await _writer.FlushAsync(cancellationToken).ConfigureAwait(false); +#else + await _writer.WriteAsync("").ConfigureAwait(false); + await _writer.FlushAsync().ConfigureAwait(false); #endif - ).ConfigureAwait(false); return []; } var rowsWritten = await WriteValuesAsync(_writer, _value, seperator, newLine, progress, cancellationToken).ConfigureAwait(false); await _writer.FlushAsync( -#if NET5_0_OR_GREATER +#if NET cancellationToken #endif ).ConfigureAwait(false); @@ -200,23 +182,23 @@ public async Task InsertAsync(bool overwriteSheet = false, IProgress? return rowsWritten.FirstOrDefault(); } - public string ToCsvString(object? value, MiniExcelColumnMapping? p) + private string ToCsvString(object? value, MiniExcelColumnMapping? mapping) { if (value is null) return ""; if (value is DateTime dateTime) { - if (p?.ExcelFormat is not null) - return dateTime.ToString(p.ExcelFormat, _configuration.Culture); + if (mapping?.ExcelFormat is not null) + return dateTime.ToString(mapping.ExcelFormat, _configuration.Culture); return _configuration.Culture.Equals(CultureInfo.InvariantCulture) ? dateTime.ToString("yyyy-MM-dd HH:mm:ss", _configuration.Culture) : dateTime.ToString(_configuration.Culture); } - if (p?.ExcelFormat is not null && value is IFormattable formattableValue) - return formattableValue.ToString(p.ExcelFormat, _configuration.Culture); + if (mapping?.ExcelFormat is not null && value is IFormattable formattableValue) + return formattableValue.ToString(mapping.ExcelFormat, _configuration.Culture); return Convert.ToString(value, _configuration.Culture) ?? ""; } diff --git a/src/MiniExcel.OpenXml/Api/OpenXmlExporter.cs b/src/MiniExcel.OpenXml/Api/OpenXmlExporter.cs index b2b11d5b..035c6e67 100644 --- a/src/MiniExcel.OpenXml/Api/OpenXmlExporter.cs +++ b/src/MiniExcel.OpenXml/Api/OpenXmlExporter.cs @@ -36,12 +36,9 @@ public async Task InsertSheetAsync(string path, object value, string sheetN return rowsWritten.FirstOrDefault(); } -#if NET8_0_OR_GREATER var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.SequentialScan); -#endif + return await InsertSheetAsync(stream, value, sheetName, printHeader, overwriteSheet, configuration, progress, cancellationToken).ConfigureAwait(false); } @@ -130,16 +127,11 @@ public async Task CopyAndAddSheetAsync(string inputFile, string outputFile, if (inputFile.Equals(outputFile, StringComparison.InvariantCultureIgnoreCase)) throw new ArgumentException("The generated file must not have the same path as the original file."); - #if NET8_0_OR_GREATER var inputStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.RandomAccess); await using var disposableInputStream = inputStream.ConfigureAwait(false); var outputStream = new FileStream(outputFile, overwriteFile ? FileMode.Create : FileMode.CreateNew, FileAccess.Write, FileShare.None, 4096, FileOptions.SequentialScan); await using var disposableOutputStream = outputStream.ConfigureAwait(false); - #else - using var inputStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.RandomAccess); - using var outputStream = new FileStream(outputFile, mode: overwriteFile ? FileMode.Create : FileMode.CreateNew, FileAccess.Write, FileShare.None, 4096, FileOptions.SequentialScan); - #endif return await CopyAndAddSheetAsync(inputStream, outputStream, value, sheetName, printHeader, overwriteSheet, configuration, progress, cancellationToken).ConfigureAwait(false); } @@ -164,12 +156,9 @@ public async Task ExportAsync(string path, object value, bool printHeader if (Path.GetExtension(path).Equals(".xlsm", StringComparison.InvariantCultureIgnoreCase)) throw new NotSupportedException("MiniExcel's Export does not support the .xlsm format"); -#if NET8_0_OR_GREATER var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = overwriteFile ? File.Create(path) : new FileStream(path, FileMode.CreateNew); -#endif + return await ExportAsync(stream, value, printHeader, sheetName, configuration, progress, cancellationToken).ConfigureAwait(false); } @@ -210,12 +199,9 @@ public async Task ExportAsync(Stream stream, object value, bool printHead [CreateSyncVersion] public async Task AlterSheetAsync(string path, string sheetName, string? newSheetName = null, int? newSheetIndex = null, SheetState? newSheetState = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); -#endif + await AlterSheetAsync(stream, sheetName, newSheetName, newSheetIndex, newSheetState, cancellationToken).ConfigureAwait(false); } diff --git a/src/MiniExcel.OpenXml/Api/OpenXmlImporter.cs b/src/MiniExcel.OpenXml/Api/OpenXmlImporter.cs index 738db2f0..aaf53100 100644 --- a/src/MiniExcel.OpenXml/Api/OpenXmlImporter.cs +++ b/src/MiniExcel.OpenXml/Api/OpenXmlImporter.cs @@ -1,4 +1,4 @@ -using MiniExcelLib.Core; + // ReSharper disable once CheckNamespace namespace MiniExcelLib.OpenXml; @@ -14,12 +14,9 @@ public async IAsyncEnumerable QueryAsync(string path, string? sheetName = string startCell = "A1", bool treatHeaderAsData = false, OpenXmlConfiguration? configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new() { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + var query = QueryAsync(stream, sheetName, startCell, treatHeaderAsData, configuration, cancellationToken); await foreach (var item in query.ConfigureAwait(false)) @@ -41,12 +38,8 @@ public async IAsyncEnumerable QueryAsync(string path, bool useHeaderRow string? sheetName = null, string startCell = "A1", OpenXmlConfiguration? configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif await foreach (var item in QueryAsync(stream, useHeaderRow, sheetName, startCell, configuration, cancellationToken).ConfigureAwait(false)) yield return item; @@ -79,12 +72,9 @@ public async IAsyncEnumerable QueryRangeAsync(string path, bool useHead string? sheetName = null, string startCell = "A1", string endCell = "", OpenXmlConfiguration? configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + await foreach (var item in QueryRangeAsync(stream, useHeaderRow, sheetName, startCell, endCell, configuration, cancellationToken).ConfigureAwait(false)) yield return item; } @@ -105,12 +95,9 @@ public async IAsyncEnumerable QueryRangeAsync(string path, bool useHead int? endColumnIndex = null, OpenXmlConfiguration? configuration = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + await foreach (var item in QueryRangeAsync(stream, useHeaderRow, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, configuration, cancellationToken).ConfigureAwait(false)) yield return item; } @@ -138,12 +125,9 @@ public async Task QueryAsDataTableAsync(string path, bool useHeaderRo string? sheetName = null, string startCell = "A1", OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + return await QueryAsDataTableAsync(stream, useHeaderRow, sheetName, startCell, configuration, cancellationToken).ConfigureAwait(false); } @@ -208,12 +192,9 @@ public async Task QueryAsDataTableAsync(Stream stream, bool useHeader [CreateSyncVersion] public async Task> GetSheetNamesAsync(string path, OpenXmlConfiguration? config = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + return await GetSheetNamesAsync(stream, config, cancellationToken).ConfigureAwait(false); } @@ -233,12 +214,9 @@ public async Task> GetSheetNamesAsync(Stream stream, OpenXmlConfigu [CreateSyncVersion] public async Task> GetSheetInformationsAsync(string path, OpenXmlConfiguration? config = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + return await GetSheetInformationsAsync(stream, config, cancellationToken).ConfigureAwait(false); } @@ -258,12 +236,9 @@ public async Task> GetSheetInformationsAsync(Stream stream, Open [CreateSyncVersion] public async Task> GetSheetDimensionsAsync(string path, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + return await GetSheetDimensionsAsync(stream, cancellationToken).ConfigureAwait(false); } @@ -279,12 +254,9 @@ public async Task> GetColumnNamesAsync(string path, bool use string? sheetName = null, string startCell = "A1", OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + return await GetColumnNamesAsync(stream, useHeaderRow, sheetName, startCell, configuration, cancellationToken).ConfigureAwait(false); } @@ -305,12 +277,9 @@ public async Task> GetColumnNamesAsync(Stream stream, bool u [CreateSyncVersion] public async Task RetrieveCommentsAsync(string path, string? sheetName, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = FileHelper.OpenSharedRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = FileHelper.OpenSharedRead(path); -#endif + return await RetrieveCommentsAsync(stream, sheetName, cancellationToken).ConfigureAwait(false); } diff --git a/src/MiniExcel.OpenXml/Api/OpenXmlTemplater.cs b/src/MiniExcel.OpenXml/Api/OpenXmlTemplater.cs index dd6d486f..61932cdc 100644 --- a/src/MiniExcel.OpenXml/Api/OpenXmlTemplater.cs +++ b/src/MiniExcel.OpenXml/Api/OpenXmlTemplater.cs @@ -12,12 +12,9 @@ internal OpenXmlTemplater() { } [CreateSyncVersion] public async Task AddPictureAsync(string path, CancellationToken cancellationToken = default, params MiniExcelPicture[] images) { -#if NET8_0_OR_GREATER var stream = File.Open(path, FileMode.OpenOrCreate); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = File.Open(path, FileMode.OpenOrCreate); -#endif + await MiniExcelPictureImplement.AddPictureAsync(stream, cancellationToken, images).ConfigureAwait(false); } @@ -31,12 +28,9 @@ public async Task AddPictureAsync(Stream excelStream, CancellationToken cancella public async Task FillTemplateAsync(string path, string templatePath, object value, bool overwriteFile = false, OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = overwriteFile ? File.Create(path) : File.Open(path, FileMode.CreateNew); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = overwriteFile ? File.Create(path) : File.Open(path, FileMode.CreateNew); -#endif + await FillTemplateAsync(stream, templatePath, value, configuration, cancellationToken).ConfigureAwait(false); } @@ -44,12 +38,8 @@ public async Task FillTemplateAsync(string path, string templatePath, object val public async Task FillTemplateAsync(string path, Stream templateStream, object value, bool overwriteFile = false, OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = overwriteFile ? File.Create(path) : File.Open(path, FileMode.CreateNew); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = overwriteFile ? File.Create(path) : File.Open(path, FileMode.CreateNew); -#endif var template = GetOpenXmlTemplate(stream, configuration); await template.SaveAsByTemplateAsync(templateStream, value, cancellationToken).ConfigureAwait(false); @@ -75,12 +65,9 @@ public async Task FillTemplateAsync(Stream stream, Stream templateStream, object public async Task FillTemplateAsync(string path, byte[] templateBytes, object value, bool overwriteFile = false, OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = overwriteFile ? File.Create(path) : File.Open(path, FileMode.CreateNew); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = overwriteFile ? File.Create(path) : File.Open(path, FileMode.CreateNew); -#endif + await FillTemplateAsync(stream, templateBytes, value, configuration, cancellationToken).ConfigureAwait(false); } @@ -98,12 +85,9 @@ public async Task FillTemplateAsync(Stream stream, byte[] templateBytes, object public async Task MergeSameCellsAsync(string mergedFilePath, string path, OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = File.Create(mergedFilePath); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = File.Create(mergedFilePath); -#endif + await MergeSameCellsAsync(stream, path, configuration, cancellationToken).ConfigureAwait(false); } @@ -131,48 +115,4 @@ private static OpenXmlTemplate GetOpenXmlTemplate(Stream stream, OpenXmlConfigur } #endregion - - #region Obsolete - [CreateSyncVersion, Obsolete("Please use FillTemplate or FillTemplateAsync instead")] - public Task ApplyTemplateAsync(string path, string templatePath, object value, - OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) - { - return FillTemplateAsync(path, templatePath, value, true, configuration, cancellationToken); - } - - [CreateSyncVersion, Obsolete("Please use FillTemplate or FillTemplateAsync instead")] - public Task ApplyTemplateAsync(string path, Stream templateStream, object value, - OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) - { - return FillTemplateAsync(path, templateStream, value, true, configuration, cancellationToken); - } - - [CreateSyncVersion, Obsolete("Please use FillTemplate or FillTemplateAsync instead")] - public Task ApplyTemplateAsync(Stream stream, string templatePath, object value, - OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) - { - return FillTemplateAsync(stream, templatePath, value, configuration, cancellationToken); - } - - [CreateSyncVersion, Obsolete("Please use FillTemplate or FillTemplateAsync instead")] - public Task ApplyTemplateAsync(Stream stream, Stream templateStream, object value, - OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) - { - return FillTemplateAsync(stream, templateStream, value, configuration, cancellationToken); - } - - [CreateSyncVersion, Obsolete("Please use FillTemplate or FillTemplateAsync instead")] - public Task ApplyTemplateAsync(string path, byte[] templateBytes, object value, - OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) - { - return FillTemplateAsync(path, templateBytes, value, true, configuration, cancellationToken); - } - - [CreateSyncVersion, Obsolete("Please use FillTemplate or FillTemplateAsync instead")] - public Task ApplyTemplateAsync(Stream stream, byte[] templateBytes, object value, - OpenXmlConfiguration? configuration = null, CancellationToken cancellationToken = default) - { - return FillTemplateAsync(stream, templateBytes, value, configuration, cancellationToken); - } - #endregion -} \ No newline at end of file +} diff --git a/src/MiniExcel.OpenXml/Api/ProviderExtensions.cs b/src/MiniExcel.OpenXml/Api/ProviderExtensions.cs index 782f71ba..da617808 100644 --- a/src/MiniExcel.OpenXml/Api/ProviderExtensions.cs +++ b/src/MiniExcel.OpenXml/Api/ProviderExtensions.cs @@ -1,4 +1,4 @@ -using MiniExcelLib.Core; + // ReSharper disable once CheckNamespace namespace MiniExcelLib.OpenXml; diff --git a/src/MiniExcel.OpenXml/Constants/ExcelContentTypes.cs b/src/MiniExcel.OpenXml/Constants/ExcelContentTypes.cs index dcef2d61..9f207e4d 100644 --- a/src/MiniExcel.OpenXml/Constants/ExcelContentTypes.cs +++ b/src/MiniExcel.OpenXml/Constants/ExcelContentTypes.cs @@ -3,9 +3,10 @@ internal static class ExcelContentTypes { internal const string Relationships = "application/vnd.openxmlformats-package.relationships+xml"; - internal const string SharedStrings = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"; + internal const string Workbook = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"; internal const string Worksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"; + internal const string SharedStrings = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"; internal const string Styles = "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"; internal const string Drawing = "application/vnd.openxmlformats-officedocument.drawing+xml"; - internal const string Workbook = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"; -} \ No newline at end of file + internal const string Table = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"; +} diff --git a/src/MiniExcel.OpenXml/Constants/ExcelDataTypes.cs b/src/MiniExcel.OpenXml/Constants/ExcelDataTypes.cs new file mode 100644 index 00000000..0541c6f6 --- /dev/null +++ b/src/MiniExcel.OpenXml/Constants/ExcelDataTypes.cs @@ -0,0 +1,12 @@ +namespace MiniExcelLib.OpenXml.Constants; + +internal static class ExcelDataTypes +{ + internal const string InlineString = "inlineStr"; + internal const string CalculatedString = "str"; + internal const string SharedString = "s"; + internal const string Numeric = "n"; + internal const string Boolean = "b"; + internal const string DateTime = "d"; + internal const string Error = "e"; +} diff --git a/src/MiniExcel.OpenXml/Constants/ExcelFileNames.cs b/src/MiniExcel.OpenXml/Constants/ExcelFileNames.cs index eb5d7947..e38c5add 100644 --- a/src/MiniExcel.OpenXml/Constants/ExcelFileNames.cs +++ b/src/MiniExcel.OpenXml/Constants/ExcelFileNames.cs @@ -8,12 +8,15 @@ internal static class ExcelFileNames internal const string ContentTypes = "[Content_Types].xml"; internal const string Person = "xl/persons/person.xml"; internal const string Styles = "xl/styles.xml"; + internal const string CalcChain = "xl/calcChain.xml"; + internal const string Workbook = "xl/workbook.xml"; internal const string WorkbookRels = "xl/_rels/workbook.xml.rels"; internal const string WorksheetBase = "xl/worksheets/sheet"; - + internal static string Worksheet(int sheetId) => $"xl/worksheets/sheet{sheetId}.xml"; internal static string SheetRels(int sheetId) => $"xl/worksheets/_rels/sheet{sheetId}.xml.rels"; - internal static string Drawing(int sheetIndex) => $"xl/drawings/drawing{sheetIndex + 1}.xml"; - internal static string DrawingRels(int sheetIndex) => $"xl/drawings/_rels/drawing{sheetIndex + 1}.xml.rels"; + internal static string Drawing(int sheetIndex) => $"xl/drawings/drawing{sheetIndex}.xml"; + internal static string DrawingRels(int sheetIndex) => $"xl/drawings/_rels/drawing{sheetIndex}.xml.rels"; + internal static string Table(int tableIndex) => $"xl/tables/table{tableIndex}.xml"; } diff --git a/src/MiniExcel.OpenXml/Constants/ExcelXml.cs b/src/MiniExcel.OpenXml/Constants/ExcelXml.cs index 13ba39dd..b9e2e183 100644 --- a/src/MiniExcel.OpenXml/Constants/ExcelXml.cs +++ b/src/MiniExcel.OpenXml/Constants/ExcelXml.cs @@ -11,12 +11,6 @@ static ExcelXml() DefaultDrawing = XmlHelper.MinifyXml(DefaultDrawing); } - internal const string InlineStringDataType = "inlineStr"; - internal const string CalculatedStringDataType = "str"; - internal const string SharedStringDataType = "s"; - internal const string NumericDataType = "n"; - internal const string BooleanDataType = "b"; - internal const string EmptySheetXml = """"""; internal static readonly string DefaultRels = diff --git a/src/MiniExcel.OpenXml/Constants/Schemas.cs b/src/MiniExcel.OpenXml/Constants/Schemas.cs index 88d436a4..622b5eea 100644 --- a/src/MiniExcel.OpenXml/Constants/Schemas.cs +++ b/src/MiniExcel.OpenXml/Constants/Schemas.cs @@ -8,8 +8,14 @@ internal static class Schemas public const string OpenXmlPackageRelationships = "http://schemas.openxmlformats.org/package/2006/relationships"; public const string SpreadsheetmlXmlRelationships = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; public const string SpreadsheetmlXmlStrictRelationships = "http://purl.oclc.org/ooxml/officeDocument/relationships"; - public const string SpreadsheetmlXmlComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"; - public const string SpreadsheetmlXmlThreadedComment = "http://schemas.microsoft.com/office/2017/10/relationships/threadedComment"; + public const string SpreadsheetmlXmlSpreadsheetDrawing = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"; + public const string SpreadsheetmlXmlDrawingml2006 = "http://schemas.openxmlformats.org/drawingml/2006/main"; + public const string SpreadsheetmlXmlDrawing2014 = "http://schemas.microsoft.com/office/drawing/2014/main"; + public const string SpreadsheetmlXmlDrawingRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"; + public const string SpreadsheetmlXmlImageRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; + public const string SpreadsheetmlXmlTableRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"; + public const string SpreadsheetmlXmlCommentsRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"; + public const string SpreadsheetmlXmlThreadedCommentRelationship = "http://schemas.microsoft.com/office/2017/10/relationships/threadedComment"; public const string SpreadsheetmlXmlX14Ac = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"; public const string SpreadsheetmlXmlX18Tc = "http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments"; diff --git a/src/MiniExcel.OpenXml/Constants/WorksheetXml.cs b/src/MiniExcel.OpenXml/Constants/WorksheetXml.cs index fdfbee8a..39a1dffb 100644 --- a/src/MiniExcel.OpenXml/Constants/WorksheetXml.cs +++ b/src/MiniExcel.OpenXml/Constants/WorksheetXml.cs @@ -1,6 +1,4 @@ -using MiniExcelLib.Core.Attributes; - -namespace MiniExcelLib.OpenXml.Constants; +namespace MiniExcelLib.OpenXml.Constants; internal static class WorksheetXml { @@ -57,13 +55,13 @@ internal static string Cell(string cellReference, string? cellType, string style return cellType switch { _ when columnType == ColumnType.Formula - => $"""{XmlHelper.EncodeXml(cellValue)}""", + => $"""{XmlHelper.EncodeXml(cellValue)}""", - ExcelXml.InlineStringDataType - => $"""{XmlHelper.EncodeXml(cellValue)}""", + ExcelDataTypes.InlineString + => $"""{XmlHelper.EncodeXml(cellValue)}""", - ExcelXml.SharedStringDataType - => $"""{cellValue}""", + ExcelDataTypes.SharedString + => $"""{cellValue}""", _ => $"""{cellValue}""" }; diff --git a/src/MiniExcel.OpenXml/FluentMapping/Api/MappingExporter.cs b/src/MiniExcel.OpenXml/FluentMapping/Api/MappingExporter.cs index 5cfed4c6..855dc066 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Api/MappingExporter.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Api/MappingExporter.cs @@ -19,12 +19,8 @@ public async Task ExportAsync(string path, IEnumerable? values, bool overw { var filePath = path.EndsWith(".xlsx", StringComparison.InvariantCultureIgnoreCase) ? path : $"{path}.xlsx" ; -#if NET8_0_OR_GREATER var stream = overwriteFile ? File.Create(filePath) : new FileStream(filePath, FileMode.CreateNew); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = overwriteFile ? File.Create(filePath) : new FileStream(filePath, FileMode.CreateNew); -#endif await ExportAsync(stream, values, cancellationToken).ConfigureAwait(false); } diff --git a/src/MiniExcel.OpenXml/FluentMapping/Api/MappingImporter.cs b/src/MiniExcel.OpenXml/FluentMapping/Api/MappingImporter.cs index d6427048..affafd18 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Api/MappingImporter.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Api/MappingImporter.cs @@ -12,12 +12,8 @@ public MappingImporter(MappingRegistry registry) : this() [CreateSyncVersion] public async IAsyncEnumerable QueryAsync(string path, [EnumeratorCancellation] CancellationToken cancellationToken = default) where T : class, new() { - #if NET8_0_OR_GREATER var stream = File.OpenRead(path); await using var disposableStream = stream.ConfigureAwait(false); - #else - using var stream = File.OpenRead(path); - #endif await foreach (var item in QueryAsync(stream, cancellationToken).ConfigureAwait(false)) yield return item; @@ -39,12 +35,9 @@ public MappingImporter(MappingRegistry registry) : this() [CreateSyncVersion] public async Task QuerySingleAsync(string path, CancellationToken cancellationToken = default) where T : class, new() { -#if NET8_0_OR_GREATER var stream = File.OpenRead(path); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = File.OpenRead(path); -#endif + return await QuerySingleAsync(stream, cancellationToken).ConfigureAwait(false); } @@ -64,4 +57,4 @@ public MappingImporter(MappingRegistry registry) : this() throw new InvalidOperationException("No data found."); } -} \ No newline at end of file +} diff --git a/src/MiniExcel.OpenXml/FluentMapping/Api/MappingTemplater.cs b/src/MiniExcel.OpenXml/FluentMapping/Api/MappingTemplater.cs index 248f9702..cb32fa2b 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Api/MappingTemplater.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Api/MappingTemplater.cs @@ -23,16 +23,12 @@ public async Task FillTemplateAsync( if (values is null) throw new ArgumentNullException(nameof(values)); -#if NET8_0_OR_GREATER var outputStream = File.Create(outputPath); await using var disposableOutputStream = outputStream.ConfigureAwait(false); var templateStream = File.OpenRead(templatePath); await using var disposableTemplateStream = templateStream.ConfigureAwait(false); -#else - using var outputStream = File.Create(outputPath); - using var templateStream = File.OpenRead(templatePath); -#endif + await FillTemplateAsync(outputStream, templateStream, values, cancellationToken).ConfigureAwait(false); } @@ -73,12 +69,9 @@ public async Task FillTemplateAsync( if (values is null) throw new ArgumentNullException(nameof(values)); -#if NET8_0_OR_GREATER var templateStream = new MemoryStream(templateBytes); await using var disposableTemplateStream = templateStream.ConfigureAwait(false); -#else - using var templateStream = new MemoryStream(templateBytes); -#endif + await FillTemplateAsync(outputStream, templateStream, values, cancellationToken).ConfigureAwait(false); } @@ -115,3 +108,4 @@ public Task ApplyTemplateAsync( } #endregion } + diff --git a/src/MiniExcel.OpenXml/FluentMapping/Api/ProviderExtensions.cs b/src/MiniExcel.OpenXml/FluentMapping/Api/ProviderExtensions.cs index 1a4a502e..19391f5c 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Api/ProviderExtensions.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Api/ProviderExtensions.cs @@ -1,5 +1,3 @@ -using MiniExcelLib.Core; - namespace MiniExcelLib.OpenXml.FluentMapping.Api; public static class ProviderExtensions diff --git a/src/MiniExcel.OpenXml/FluentMapping/CompiledMapping.cs b/src/MiniExcel.OpenXml/FluentMapping/CompiledMapping.cs index 322e2e51..a5daa206 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/CompiledMapping.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/CompiledMapping.cs @@ -1,5 +1,3 @@ -using System.Collections; - namespace MiniExcelLib.OpenXml.FluentMapping; internal class CompiledMapping diff --git a/src/MiniExcel.OpenXml/FluentMapping/Configuration/CollectionMappingBuilder.cs b/src/MiniExcel.OpenXml/FluentMapping/Configuration/CollectionMappingBuilder.cs index 9cae1c35..13fa931c 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Configuration/CollectionMappingBuilder.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Configuration/CollectionMappingBuilder.cs @@ -1,11 +1,10 @@ -using System.Collections; using System.Text.RegularExpressions; namespace MiniExcelLib.OpenXml.FluentMapping.Configuration; internal partial class CollectionMappingBuilder : ICollectionMappingBuilder where TCollection : IEnumerable { -#if NET7_0_OR_GREATER +#if NET [GeneratedRegex("^[A-Z]+[0-9]+$")] private static partial Regex CellAddressRegexImpl(); private static readonly Regex CellAddressRegex = CellAddressRegexImpl(); #else @@ -56,4 +55,4 @@ public ICollectionMappingBuilder WithItemMapping(Action where TCollection : IEnumerable diff --git a/src/MiniExcel.OpenXml/FluentMapping/Configuration/IMappingConfiguration.cs b/src/MiniExcel.OpenXml/FluentMapping/Configuration/IMappingConfiguration.cs index 01c18bb7..2738ec55 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Configuration/IMappingConfiguration.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Configuration/IMappingConfiguration.cs @@ -1,6 +1,3 @@ -using System.Collections; -using System.Linq.Expressions; - namespace MiniExcelLib.OpenXml.FluentMapping.Configuration; public interface IMappingConfiguration diff --git a/src/MiniExcel.OpenXml/FluentMapping/Configuration/MappingConfiguration.cs b/src/MiniExcel.OpenXml/FluentMapping/Configuration/MappingConfiguration.cs index 7322cde7..ba4432a8 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Configuration/MappingConfiguration.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Configuration/MappingConfiguration.cs @@ -1,6 +1,3 @@ -using System.Collections; -using System.Linq.Expressions; - namespace MiniExcelLib.OpenXml.FluentMapping.Configuration; internal class MappingConfiguration : IMappingConfiguration diff --git a/src/MiniExcel.OpenXml/FluentMapping/Configuration/PropertyMappingBuilder.cs b/src/MiniExcel.OpenXml/FluentMapping/Configuration/PropertyMappingBuilder.cs index df514ec3..03e0eb9b 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Configuration/PropertyMappingBuilder.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Configuration/PropertyMappingBuilder.cs @@ -4,7 +4,7 @@ namespace MiniExcelLib.OpenXml.FluentMapping.Configuration; internal partial class PropertyMappingBuilder : IPropertyMappingBuilder { -#if NET7_0_OR_GREATER +#if NET [GeneratedRegex("^[A-Z]+[0-9]+$")] private static partial Regex CellAddressRegexImpl(); private static readonly Regex CellAddressRegex = CellAddressRegexImpl(); #else @@ -42,4 +42,4 @@ public IPropertyMappingBuilder WithFormula(string formula) _mapping.Formula = formula; return this; } -} \ No newline at end of file +} diff --git a/src/MiniExcel.OpenXml/FluentMapping/Helpers/ConversionHelper.cs b/src/MiniExcel.OpenXml/FluentMapping/Helpers/ConversionHelper.cs index 45da6d89..40089cae 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Helpers/ConversionHelper.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Helpers/ConversionHelper.cs @@ -1,6 +1,5 @@ using System.Collections.Concurrent; using System.Globalization; -using System.Linq.Expressions; using System.Reflection; namespace MiniExcelLib.OpenXml.FluentMapping.Helpers; diff --git a/src/MiniExcel.OpenXml/FluentMapping/Helpers/MappingMetadataExtractor.cs b/src/MiniExcel.OpenXml/FluentMapping/Helpers/MappingMetadataExtractor.cs index 0cd44fd5..0a260557 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/Helpers/MappingMetadataExtractor.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/Helpers/MappingMetadataExtractor.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Reflection; using MiniExcelLib.Core.Helpers; using MiniExcelLib.Core.Reflection; diff --git a/src/MiniExcel.OpenXml/FluentMapping/MappingCellStream.cs b/src/MiniExcel.OpenXml/FluentMapping/MappingCellStream.cs index 4f382695..403cd52c 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/MappingCellStream.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/MappingCellStream.cs @@ -1,4 +1,3 @@ -using System.Collections; using MiniExcelLib.Core.Abstractions; namespace MiniExcelLib.OpenXml.FluentMapping; diff --git a/src/MiniExcel.OpenXml/FluentMapping/MappingCompiler.cs b/src/MiniExcel.OpenXml/FluentMapping/MappingCompiler.cs index b7dbae53..efc5b6c3 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/MappingCompiler.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/MappingCompiler.cs @@ -1,5 +1,3 @@ -using System.Collections; -using System.Linq.Expressions; using System.Reflection; using MiniExcelLib.Core.Helpers; using MiniExcelLib.Core.Reflection; diff --git a/src/MiniExcel.OpenXml/FluentMapping/MappingReader.cs b/src/MiniExcel.OpenXml/FluentMapping/MappingReader.cs index bf1181c2..611f9f1b 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/MappingReader.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/MappingReader.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Runtime.CompilerServices; using Zomp.SyncMethodGenerator; diff --git a/src/MiniExcel.OpenXml/FluentMapping/MappingTemplateApplicator.cs b/src/MiniExcel.OpenXml/FluentMapping/MappingTemplateApplicator.cs index 1d9bcdd6..2936994f 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/MappingTemplateApplicator.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/MappingTemplateApplicator.cs @@ -24,11 +24,11 @@ public static async Task ApplyTemplateAsync( { // Copy to memory stream if not seekable var memStream = new MemoryStream(); -#if NETCOREAPP2_1_OR_GREATER - await templateStream.CopyToAsync(memStream, cancellationToken).ConfigureAwait(false); -#else - await templateStream.CopyToAsync(memStream).ConfigureAwait(false); + await templateStream.CopyToAsync(memStream +#if NET + , cancellationToken #endif + ).ConfigureAwait(false); memStream.Position = 0; templateStream = memStream; } @@ -88,7 +88,7 @@ await ProcessWorksheetAsync( private static bool IsWorksheetEntry(string fullName) { - return fullName.StartsWith("xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase) && + return fullName.StartsWith(ExcelFileNames.WorksheetBase, StringComparison.OrdinalIgnoreCase) && fullName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase); } @@ -111,20 +111,13 @@ private static async Task CopyEntryAsync( targetEntry.LastWriteTime = sourceEntry.LastWriteTime; // Copy content -#if NET8_0_OR_GREATER var sourceStream = await sourceEntry.OpenAsync(cancellationToken).ConfigureAwait(false); - var targetStream = await targetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); - await using var disposableSourceStream = sourceStream.ConfigureAwait(false); - await using var disposableTargetStream = targetStream.ConfigureAwait(false); - await sourceStream.CopyToAsync(targetStream, cancellationToken).ConfigureAwait(false); -#else - using var sourceStream = sourceEntry.Open(); - using var targetStream = targetEntry.Open(); + var targetStream = await targetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); + await using var disposableTargetStream = targetStream.ConfigureAwait(false); - await sourceStream.CopyToAsync(targetStream).ConfigureAwait(false); -#endif + await sourceStream.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false); } [CreateSyncVersion] @@ -141,16 +134,11 @@ private static async Task ProcessWorksheetAsync( targetEntry.LastWriteTime = sourceEntry.LastWriteTime; // Open streams -#if NET8_0_OR_GREATER var sourceStream = await sourceEntry.OpenAsync(cancellationToken).ConfigureAwait(false); - var targetStream = await targetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); - await using var disposableSourceStream = sourceStream.ConfigureAwait(false); + + var targetStream = await targetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableTargetStream = targetStream.ConfigureAwait(false); -#else - using var sourceStream = sourceEntry.Open(); - using var targetStream = targetEntry.Open(); -#endif // Create processor for this worksheet var processor = new MappingTemplateProcessor(mapping); @@ -165,4 +153,4 @@ await processor.ProcessSheetAsync( enumerator, cancellationToken).ConfigureAwait(false); } -} \ No newline at end of file +} diff --git a/src/MiniExcel.OpenXml/FluentMapping/NestedMappingInfo.cs b/src/MiniExcel.OpenXml/FluentMapping/NestedMappingInfo.cs index 300918a1..cef573d1 100644 --- a/src/MiniExcel.OpenXml/FluentMapping/NestedMappingInfo.cs +++ b/src/MiniExcel.OpenXml/FluentMapping/NestedMappingInfo.cs @@ -1,5 +1,3 @@ -using System.Collections; - namespace MiniExcelLib.OpenXml.FluentMapping; /// diff --git a/src/MiniExcel.OpenXml/GlobalUsings.cs b/src/MiniExcel.OpenXml/GlobalUsings.cs index c8bc554b..35a30d40 100644 --- a/src/MiniExcel.OpenXml/GlobalUsings.cs +++ b/src/MiniExcel.OpenXml/GlobalUsings.cs @@ -1,17 +1,24 @@ // Global using directives global using System.Collections; +global using System.ComponentModel; global using System.Data; global using System.Globalization; global using System.IO.Compression; +global using System.Linq.Expressions; global using System.Reflection; global using System.Runtime.CompilerServices; global using System.Text; global using System.Text.RegularExpressions; global using System.Xml; +global using System.Xml.Linq; +global using MiniExcelLib.Core; global using MiniExcelLib.Core.Abstractions; +global using MiniExcelLib.Core.Attributes; +global using MiniExcelLib.Core.Enums; global using MiniExcelLib.Core.Helpers; global using MiniExcelLib.Core.Reflection; +global using MiniExcelLib.OpenXml.Constants; global using MiniExcelLib.OpenXml.Helpers; global using MiniExcelLib.OpenXml.Models; global using MiniExcelLib.OpenXml.Utils; diff --git a/src/MiniExcel.OpenXml/Helpers/XmlHelper.cs b/src/MiniExcel.OpenXml/Helpers/XmlHelper.cs index 04a3a4ef..48baaadc 100644 --- a/src/MiniExcel.OpenXml/Helpers/XmlHelper.cs +++ b/src/MiniExcel.OpenXml/Helpers/XmlHelper.cs @@ -3,7 +3,7 @@ /// XmlEncoder MIT Copyright ©2021 from https://github.com/ClosedXML internal static partial class XmlHelper { -#if NET7_0_OR_GREATER +#if NET [GeneratedRegex("_(x[\\dA-Fa-f]{4})_", RegexOptions.Compiled)] private static partial Regex X4LRegexImpl(); private static readonly Regex X4LRegex = X4LRegexImpl(); @@ -59,4 +59,4 @@ public static string EncodeXml(string? value) => value is null ? "" .Replace("\"", """) .Replace("'", "'") .ToString() ?? ""; -} \ No newline at end of file +} diff --git a/src/MiniExcel.OpenXml/Models/SheetDto.cs b/src/MiniExcel.OpenXml/Models/SheetDto.cs index 1bea641f..99f14e21 100644 --- a/src/MiniExcel.OpenXml/Models/SheetDto.cs +++ b/src/MiniExcel.OpenXml/Models/SheetDto.cs @@ -5,7 +5,7 @@ internal class SheetDto internal string ID { get; set; } = $"R{Guid.NewGuid():N}"; internal string? Name { get; set; } internal int SheetIdx { get; set; } - internal string Path => $"xl/worksheets/sheet{SheetIdx}.xml"; + internal string Path => ExcelFileNames.Worksheet(SheetIdx); internal string State { get; set; } -} \ No newline at end of file +} diff --git a/src/MiniExcel.OpenXml/OpenXmlConfiguration.cs b/src/MiniExcel.OpenXml/OpenXmlConfiguration.cs index 586483bb..20babe76 100644 --- a/src/MiniExcel.OpenXml/OpenXmlConfiguration.cs +++ b/src/MiniExcel.OpenXml/OpenXmlConfiguration.cs @@ -1,4 +1,3 @@ -using MiniExcelLib.Core; using MiniExcelLib.OpenXml.Styles; namespace MiniExcelLib.OpenXml; diff --git a/src/MiniExcel.OpenXml/OpenXmlReader.cs b/src/MiniExcel.OpenXml/OpenXmlReader.cs index 0606099d..ab514bef 100644 --- a/src/MiniExcel.OpenXml/OpenXmlReader.cs +++ b/src/MiniExcel.OpenXml/OpenXmlReader.cs @@ -1,7 +1,4 @@ using System.Collections.ObjectModel; -using System.Xml.Linq; -using MiniExcelLib.Core; -using MiniExcelLib.OpenXml.Constants; using MiniExcelLib.OpenXml.Styles; using MiniExcelMapper = MiniExcelLib.Core.Reflection.MiniExcelMapper; using XmlReaderHelper = MiniExcelLib.OpenXml.Utils.XmlReaderHelper; @@ -178,12 +175,9 @@ internal static async Task CreateAsync(Stream stream, IMiniExcelC maxColumnIndex = endColumnIndex.Value; } -#if NET8_0_OR_GREATER var sheetStream = await sheetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableSheetStream = sheetStream.ConfigureAwait(false); -#else - using var sheetStream = sheetEntry.Open(); -#endif + using var reader = XmlReader.Create(sheetStream, xmlSettings); if (!reader.IsStartElement("worksheet", Ns)) @@ -417,13 +411,10 @@ private async Task SetSharedStringsAsync(CancellationToken cancellationToken = d if (Archive.GetEntry(ExcelFileNames.SharedStrings) is not { } sharedStringsEntry) return; - var idx = 0; -#if NET8_0_OR_GREATER var stream = await sharedStringsEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = sharedStringsEntry.Open(); -#endif + + var idx = 0; if (_config.EnableSharedStringCache && sharedStringsEntry.Length >= _config.SharedStringCacheSize) { SharedStrings = new SharedStringsDiskCache(_config.SharedStringCachePath); @@ -459,12 +450,9 @@ private static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCol ); var entry = entries.Single(w => w.FullName == ExcelFileNames.Workbook); -#if NET8_0_OR_GREATER var stream = await entry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = entry.Open(); -#endif + using var reader = XmlReader.Create(stream, xmlSettings); if (!reader.IsStartElement("workbook", Ns)) @@ -491,7 +479,7 @@ private static async IAsyncEnumerable ReadWorkbookAsync(ReadOnlyCol } await reader.SkipAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); @@ -521,8 +509,8 @@ await reader.SkipAsync() ); sheetCount++; await reader.SkipAsync() -#if NET6_0_OR_GREATER - .WaitAsync(cancellationToken) +#if NET + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); } @@ -556,12 +544,9 @@ await reader.SkipAsync() var entry = entries.Single(w => w.FullName == ExcelFileNames.WorkbookRels); -#if NET8_0_OR_GREATER var stream = await entry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = entry.Open(); -#endif + using var reader = XmlReader.Create(stream, xmlSettings); if (!XmlReaderHelper.IsStartElement(reader, "Relationships", Schemas.OpenXmlPackageRelationships)) @@ -581,7 +566,7 @@ await reader.SkipAsync() } await reader.SkipAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); @@ -648,7 +633,7 @@ private async Task ReadCellAndSetColumnIndexAsync(XmlReader reade if (reader.IsStartElement("v", Ns)) { var rawValue = await reader.ReadElementContentAsStringAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); @@ -679,7 +664,7 @@ private void ConvertCellValue(string rawValue, string aT, int xfIndex, out objec switch (aT) { - case "s": + case ExcelDataTypes.SharedString: if (int.TryParse(rawValue, style, invariantCulture, out var sstIndex)) { if (sstIndex >= 0 && sstIndex < SharedStrings?.Count) @@ -689,8 +674,7 @@ private void ConvertCellValue(string rawValue, string aT, int xfIndex, out objec } break; - case "inlineStr": - case "str": + case ExcelDataTypes.InlineString or ExcelDataTypes.CalculatedString: //TODO: it will unbox,box var v = XmlHelper.DecodeString(rawValue); value = v; @@ -711,17 +695,17 @@ private void ConvertCellValue(string rawValue, string aT, int xfIndex, out objec } break; - case "b": + case ExcelDataTypes.Boolean: value = rawValue == "1"; return; - case "d": + case ExcelDataTypes.DateTime: value = DateTime.TryParseExact(rawValue, "yyyy-MM-dd", invariantCulture, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite, out var date) ? date : rawValue; return; - case "e": + case ExcelDataTypes.Error: value = rawValue; return; @@ -759,12 +743,8 @@ internal async Task> GetDimensionsAsync(CancellationToken canc var withoutCr = false; -#if NET8_0_OR_GREATER var crSheetStream = await sheet.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableCrSheetStream = crSheetStream.ConfigureAwait(false); -#else - using var crSheetStream = sheet.Open(); -#endif using (var reader = XmlReader.Create(crSheetStream, xmlSettings)) { while (await reader.ReadAsync().ConfigureAwait(false)) @@ -812,12 +792,9 @@ internal async Task> GetDimensionsAsync(CancellationToken canc if (withoutCr) { -#if NET8_0_OR_GREATER var sheetStream = await sheet.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableSheetStream = sheetStream.ConfigureAwait(false); -#else - using var sheetStream = sheet.Open(); -#endif + using var reader = XmlReader.Create(sheetStream, xmlSettings); if (!reader.IsStartElement("worksheet", Ns)) @@ -912,16 +889,12 @@ internal static async Task TryGetMaxRowColumnIndexAs int maxRowIndex = -1; int maxColumnIndex = -1; -#if NET8_0_OR_GREATER var crSheetStream = await sheetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableCrSheetStream = crSheetStream.ConfigureAwait(false); -#else - using var crSheetStream = sheetEntry.Open(); -#endif using (var reader = XmlReader.Create(crSheetStream, xmlSettings)) { while (await reader.ReadAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false)) @@ -967,12 +940,9 @@ internal static async Task TryGetMaxRowColumnIndexAs if (withoutCr) { -#if NET8_0_OR_GREATER var sheetStream = await sheetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableSheetStream = sheetStream.ConfigureAwait(false); -#else - using var sheetStream = sheetEntry.Open(); -#endif + using var reader = XmlReader.Create(sheetStream, xmlSettings); if (!reader.IsStartElement("worksheet", Ns)) @@ -1047,12 +1017,9 @@ internal static async Task TryGetMergeCellsAsync(ZipArchiveEntry sheetEntr ); var mergeCells = new MergeCells(); -#if NET8_0_OR_GREATER var sheetStream = await sheetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableSheetStream = sheetStream.ConfigureAwait(false); -#else - using var sheetStream = sheetEntry.Open(); -#endif + using var reader = XmlReader.Create(sheetStream, xmlSettings); if (!reader.IsStartElement("worksheet", Ns)) @@ -1124,18 +1091,10 @@ internal async Task ReadCommentsAsync(string? sheetName, Cance List people = []; if (Archive.GetEntry(ExcelFileNames.Person) is { } persons) { -#if NET8_0_OR_GREATER var personStream = await persons.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposablePersonStream = personStream.ConfigureAwait(false); -#else - using var personStream = persons.Open(); -#endif -#if NETSTANDARD2_0 - var personDoc = XDocument.Load(personStream, LoadOptions.None); -#else var personDoc = await XDocument.LoadAsync(personStream, LoadOptions.None, cancellationToken).ConfigureAwait(false); -#endif var personElements = personDoc.Root?.Elements(ns18Tc + "person"); people = personElements ?.Select(p => new Author @@ -1150,26 +1109,18 @@ internal async Task ReadCommentsAsync(string? sheetName, Cance if (Archive.GetEntry($"xl/worksheets/_rels/{sheetFile}.rels") is not { } rel) return new CommentResultSet(sheetName, [], []); -#if NET8_0_OR_GREATER var stream = await rel.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = rel.Open(); -#endif - -#if NETSTANDARD2_0 - var relDoc = XDocument.Load(stream, LoadOptions.None); -#else + var relDoc = await XDocument.LoadAsync(stream, LoadOptions.None, cancellationToken).ConfigureAwait(false); -#endif var threadedCommentRels = relDoc.Root?.Elements(nsRel + "Relationship"); - var threadedCommentsElement = threadedCommentRels?.FirstOrDefault(x => x.Attribute("Type")?.Value == Schemas.SpreadsheetmlXmlThreadedComment); + var threadedCommentsElement = threadedCommentRels?.FirstOrDefault(x => x.Attribute("Type")?.Value == Schemas.SpreadsheetmlXmlThreadedCommentRelationship); var threadedCommentsTarget = threadedCommentsElement?.Attribute("Target"); var threadedCommentsPath = threadedCommentsTarget?.Value.TrimStart('.', '/'); var noteRels = relDoc.Root?.Elements(nsRel + "Relationship"); - var notesElement = noteRels?.FirstOrDefault(x => x.Attribute("Type")?.Value == Schemas.SpreadsheetmlXmlComments); + var notesElement = noteRels?.FirstOrDefault(x => x.Attribute("Type")?.Value == Schemas.SpreadsheetmlXmlCommentsRelationship); var notesTarget = notesElement?.Attribute("Target"); var notesPath = notesTarget?.Value.TrimStart('.', '/'); @@ -1178,18 +1129,10 @@ internal async Task ReadCommentsAsync(string? sheetName, Cance HashSet refCells = []; if (Archive.GetEntry($"xl/{threadedCommentsPath}") is { } threadEntry) { -#if NET8_0_OR_GREATER var threadEntryStream = await threadEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableThreadEntryStream = threadEntryStream.ConfigureAwait(false); -#else - using var threadEntryStream = threadEntry.Open(); -#endif -#if NETSTANDARD2_0 - var doc = XDocument.Load(threadEntryStream, LoadOptions.None); -#else var doc = await XDocument.LoadAsync(threadEntryStream, LoadOptions.None, cancellationToken).ConfigureAwait(false); -#endif var commentThreadElements = doc.Root?.Elements(ns18Tc + "threadedComment"); commentThreads = commentThreadElements @@ -1231,18 +1174,10 @@ internal async Task ReadCommentsAsync(string? sheetName, Cance if (Archive.GetEntry($"xl/{notesPath}") is { } noteEntry) { -#if NET8_0_OR_GREATER var noteEntryStream = await noteEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableNoteEntryStream = noteEntryStream.ConfigureAwait(false); -#else - using var noteEntryStream = noteEntry.Open(); -#endif -#if NETSTANDARD2_0 - var doc = XDocument.Load(noteEntryStream, LoadOptions.None); -#else var doc = await XDocument.LoadAsync(noteEntryStream, LoadOptions.None, cancellationToken).ConfigureAwait(false); -#endif var authorElements = doc.Root?.Element(nsMain + "authors")?.Elements(nsMain + "author"); var authors = authorElements?.Select(a => a.Value).ToArray(); @@ -1303,12 +1238,9 @@ internal async IAsyncEnumerable QueryMappedAsync( Async = true }; -#if NET8_0_OR_GREATER var sheetStream = await sheetEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableSheetStream = sheetStream.ConfigureAwait(false); -#else - using var sheetStream = sheetEntry.Open(); -#endif + using var reader = XmlReader.Create(sheetStream, xmlSettings); if (!reader.IsStartElement("worksheet", Ns)) diff --git a/src/MiniExcel.OpenXml/Picture/OpenXmlPicture.cs b/src/MiniExcel.OpenXml/Picture/OpenXmlPicture.cs index d0c38039..cda090d3 100644 --- a/src/MiniExcel.OpenXml/Picture/OpenXmlPicture.cs +++ b/src/MiniExcel.OpenXml/Picture/OpenXmlPicture.cs @@ -1,5 +1,4 @@ using System.Drawing; -using MiniExcelLib.Core.Enums; namespace MiniExcelLib.OpenXml.Picture; diff --git a/src/MiniExcel.OpenXml/Picture/OpenXmlPictureImplement.cs b/src/MiniExcel.OpenXml/Picture/OpenXmlPictureImplement.cs index ab47642f..67b15e5e 100644 --- a/src/MiniExcel.OpenXml/Picture/OpenXmlPictureImplement.cs +++ b/src/MiniExcel.OpenXml/Picture/OpenXmlPictureImplement.cs @@ -1,5 +1,4 @@ using System.Drawing; -using MiniExcelLib.Core.Enums; namespace MiniExcelLib.OpenXml.Picture; @@ -8,8 +7,8 @@ internal static partial class MiniExcelPictureImplement private static XmlNamespaceManager GetRNamespaceManager(XmlDocument doc) { var nsmgr = new XmlNamespaceManager(doc.NameTable); - nsmgr.AddNamespace("x", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"); - nsmgr.AddNamespace("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"); + nsmgr.AddNamespace("x", Schemas.SpreadsheetmlXmlMain); + nsmgr.AddNamespace("r", Schemas.SpreadsheetmlXmlRelationships); return nsmgr; } @@ -58,7 +57,7 @@ public static async Task AddPictureAsync(Stream excelStream, CancellationToken c var relsDoc = LoadXml(relsEntry); var namespaceManager = new XmlNamespaceManager(relsDoc.NameTable); - namespaceManager.AddNamespace("x", "http://schemas.openxmlformats.org/package/2006/relationships"); + namespaceManager.AddNamespace("x", Schemas.OpenXmlPackageRelationships); var xpath = $"/x:Relationships/x:Relationship[@Id='{drawingRelId}']"; var relNode = relsDoc.SelectSingleNode(xpath, namespaceManager); @@ -85,13 +84,13 @@ public static async Task AddPictureAsync(Stream excelStream, CancellationToken c var relsDoc = LoadXml(relsEntry); var relNode = relsDoc.CreateElement("Relationship", relsDoc.DocumentElement.NamespaceURI); relNode.SetAttribute("Id", drawingRelId); - relNode.SetAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"); + relNode.SetAttribute("Type", Schemas.SpreadsheetmlXmlDrawingRelationship); relNode.SetAttribute("Target", $"../drawings/drawing{drawingId}.xml"); relsDoc.DocumentElement.AppendChild(relNode); SaveXml(relsDoc, relsEntry); // Update [Content_Types].xml for drawing - var contentTypesEntry = archive.GetEntry("[Content_Types].xml"); + var contentTypesEntry = archive.GetEntry(ExcelFileNames.ContentTypes); var contentTypesDoc = LoadXml(contentTypesEntry); var overrideDrawingFileExists = contentTypesDoc.DocumentElement .ChildNodes @@ -103,7 +102,7 @@ public static async Task AddPictureAsync(Stream excelStream, CancellationToken c { var overrideNode = contentTypesDoc.CreateElement("Override", contentTypesDoc.DocumentElement.NamespaceURI); overrideNode.SetAttribute("PartName", $"/xl/drawings/drawing{drawingId}.xml"); - overrideNode.SetAttribute("ContentType", "application/vnd.openxmlformats-officedocument.drawing+xml"); + overrideNode.SetAttribute("ContentType", ExcelContentTypes.Drawing); contentTypesDoc.DocumentElement.AppendChild(overrideNode); } @@ -136,17 +135,16 @@ public static async Task AddPictureAsync(Stream excelStream, CancellationToken c var imagePath = $"xl/media/{imageName}"; var imageEntry = archive.CreateEntry(imagePath); -#if NET8_0_OR_GREATER var entryStream = await imageEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableStream = entryStream.ConfigureAwait(false); +#if NET await entryStream.WriteAsync(imageBytes.AsMemory(), cancellationToken).ConfigureAwait(false); #else - using var entryStream = imageEntry.Open(); await entryStream.WriteAsync(imageBytes, 0, imageBytes.Length, cancellationToken).ConfigureAwait(false); #endif // Step 2: Update [Content_Types].xml for image - var contentTypesEntry = archive.GetEntry("[Content_Types].xml"); + var contentTypesEntry = archive.GetEntry(ExcelFileNames.ContentTypes); var contentTypesDoc = LoadXml(contentTypesEntry); if (!contentTypesDoc.DocumentElement.InnerXml.Contains("image/png")) { @@ -164,7 +162,7 @@ public static async Task AddPictureAsync(Stream excelStream, CancellationToken c // Step 4: Add image relationship to drawing rels var relNode = drawingRelsDoc.CreateElement("Relationship", drawingRelsDoc.DocumentElement.NamespaceURI); relNode.SetAttribute("Id", relId); - relNode.SetAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"); + relNode.SetAttribute("Type", Schemas.SpreadsheetmlXmlImageRelationship); relNode.SetAttribute("Target", $"../media/{imageName}"); drawingRelsDoc.DocumentElement.AppendChild(relNode); } @@ -208,7 +206,7 @@ private static void SaveXml(XmlDocument doc, ZipArchiveEntry entry) private static XmlNamespaceManager GetNamespaceManager(XmlDocument doc) { var nsmgr = new XmlNamespaceManager(doc.NameTable); - nsmgr.AddNamespace("x", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"); + nsmgr.AddNamespace("x", Schemas.SpreadsheetmlXmlMain); return nsmgr; } @@ -219,8 +217,8 @@ private static XmlDocument CreateDrawingXml(XmlDocument existingDoc, int col, in private static class DrawingXmlHelper { - private const string XdrNamespace = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"; - private const string ANamespace = "http://schemas.openxmlformats.org/drawingml/2006/main"; + private const string XdrNamespace = Schemas.SpreadsheetmlXmlSpreadsheetDrawing; + private const string ANamespace = Schemas.SpreadsheetmlXmlDrawingml2006; private static long PixelsToEmu(int pixels) => pixels * 9525; @@ -251,7 +249,7 @@ Point location var ns = new XmlNamespaceManager(doc.NameTable); ns.AddNamespace("xdr", XdrNamespace); ns.AddNamespace("a", ANamespace); - ns.AddNamespace("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"); + ns.AddNamespace("r", Schemas.SpreadsheetmlXmlRelationships); // Root XmlElement wsDr; @@ -350,8 +348,8 @@ Point location var extNode = doc.CreateElement("a", "ext", ANamespace); extNode.SetAttribute("uri", "{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}"); - var creationId = doc.CreateElement("a16", "creationId", "http://schemas.microsoft.com/office/drawing/2014/main"); - creationId.SetAttribute("id", "http://schemas.microsoft.com/office/drawing/2014/main", $"{{00000000-0008-0000-0000-0000{nextId:D6}000000}}"); + var creationId = doc.CreateElement("a16", "creationId", Schemas.SpreadsheetmlXmlDrawing2014); + creationId.SetAttribute("id", Schemas.SpreadsheetmlXmlDrawing2014, $"{{00000000-0008-0000-0000-0000{nextId:D6}000000}}"); extNode.AppendChild(creationId); extLst.AppendChild(extNode); @@ -371,7 +369,7 @@ Point location var blipFill = doc.CreateElement("xdr", "blipFill", XdrNamespace); var blip = doc.CreateElement("a", "blip", ANamespace); - blip.SetAttribute("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"); + blip.SetAttribute("xmlns:r", Schemas.SpreadsheetmlXmlRelationships); blip.SetAttribute("embed", ns.LookupNamespace("r"), relId); blip.SetAttribute("cstate", "print"); @@ -435,4 +433,4 @@ private static void AppendXmlElement(XmlDocument doc, XmlElement parent, string parent.AppendChild(el); } } -} \ No newline at end of file +} diff --git a/src/MiniExcel.OpenXml/Styles/Builder/DefaultSheetStyleBuilder.cs b/src/MiniExcel.OpenXml/Styles/Builder/DefaultSheetStyleBuilder.cs index 191ad637..aa6f6073 100644 --- a/src/MiniExcel.OpenXml/Styles/Builder/DefaultSheetStyleBuilder.cs +++ b/src/MiniExcel.OpenXml/Styles/Builder/DefaultSheetStyleBuilder.cs @@ -1,9 +1,8 @@ using System.Drawing; -using MiniExcelLib.Core.Enums; namespace MiniExcelLib.OpenXml.Styles.Builder; -internal partial class DefaultSheetStyleBuilder(SheetStyleBuildContext context, OpenXmlStyleOptions styleOptions) : SheetStyleBuilderBase(context) +internal partial class DefaultSheetStyleBuilder(SheetStyleBuilderContext context, OpenXmlStyleOptions styleOptions) : SheetStyleBuilderBase(context) { private const HorizontalCellAlignment DefaultHorizontalAlignment = HorizontalCellAlignment.Left; private const VerticalCellAlignment DefaultVerticalAlignment = VerticalCellAlignment.Bottom; @@ -19,12 +18,8 @@ internal partial class DefaultSheetStyleBuilder(SheetStyleBuildContext context, CellXfCount = 6 }; - private readonly SheetStyleBuildContext _context = context; private readonly OpenXmlStyleOptions _styleOptions = styleOptions; - private XmlReader OldReader => _context.OldXmlReader!; - private XmlWriter NewWriter => _context.NewXmlWriter!; - protected internal override SheetStyleElementInfos GetGeneratedElementInfos() { return GeneratedElementInfos; @@ -35,7 +30,7 @@ protected override async Task GenerateNumFmtAsync() { const int numFmtIndex = 166; var index = 0; - foreach (var map in _context.SheetStyleFormatsCache.FormatMappings) + foreach (var map in Context.SheetStyleFormatsCache.FormatMappings) { index++; @@ -43,7 +38,7 @@ protected override async Task GenerateNumFmtAsync() * @@ -544,10 +539,10 @@ protected override async Task GenerateCellXfAsync() * */ await NewWriter.WriteStartElementAsync(OldReader.Prefix, "xf", OldReader.NamespaceURI).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "numFmtId", null, (numFmtIndex + i + _context.OldElementInfos.NumFmtCount).ToString()).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "fontId", null, $"{_context.OldElementInfos.FontCount}").ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "fillId", null, $"{_context.OldElementInfos.FillCount}").ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "borderId", null, $"{_context.OldElementInfos.BorderCount + 1}").ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "numFmtId", null, (numFmtIndex + i + Context.OldElementInfos.NumFmtCount).ToString()).ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "fontId", null, $"{Context.OldElementInfos.FontCount}").ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "fillId", null, $"{Context.OldElementInfos.FillCount}").ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "borderId", null, $"{Context.OldElementInfos.BorderCount + 1}").ConfigureAwait(false); await NewWriter.WriteAttributeStringAsync(null, "xfId", null, "0").ConfigureAwait(false); await NewWriter.WriteAttributeStringAsync(null, "applyNumberFormat", null, "1").ConfigureAwait(false); await NewWriter.WriteAttributeStringAsync(null, "applyFill", null, "1").ConfigureAwait(false); diff --git a/src/MiniExcel.OpenXml/Styles/Builder/MinimalSheetStyleBuilder.cs b/src/MiniExcel.OpenXml/Styles/Builder/MinimalSheetStyleBuilder.cs index cfab877f..7afce315 100644 --- a/src/MiniExcel.OpenXml/Styles/Builder/MinimalSheetStyleBuilder.cs +++ b/src/MiniExcel.OpenXml/Styles/Builder/MinimalSheetStyleBuilder.cs @@ -1,6 +1,6 @@ namespace MiniExcelLib.OpenXml.Styles.Builder; -internal partial class MinimalSheetStyleBuilder(SheetStyleBuildContext context) : SheetStyleBuilderBase(context) +internal partial class MinimalSheetStyleBuilder(SheetStyleBuilderContext context) : SheetStyleBuilderBase(context) { private static readonly SheetStyleElementInfos GenerateElementInfos = new() { @@ -11,11 +11,6 @@ internal partial class MinimalSheetStyleBuilder(SheetStyleBuildContext context) CellStyleXfCount = 1, CellXfCount = 6 }; - - private readonly SheetStyleBuildContext _context = context; - - private XmlReader OldReader => _context.OldXmlReader!; - private XmlWriter NewWriter => _context.NewXmlWriter!; protected internal override SheetStyleElementInfos GetGeneratedElementInfos() { @@ -27,7 +22,7 @@ protected override async Task GenerateNumFmtAsync() { const int numFmtIndex = 166; var index = 0; - foreach (var map in _context.SheetStyleFormatsCache.FormatMappings) + foreach (var map in Context.SheetStyleFormatsCache.FormatMappings) { index++; @@ -35,7 +30,7 @@ protected override async Task GenerateNumFmtAsync() * */ await NewWriter.WriteStartElementAsync(OldReader.Prefix, "numFmt", OldReader.NamespaceURI).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "numFmtId", null, (numFmtIndex + index + _context.OldElementInfos.NumFmtCount).ToString()).ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "numFmtId", null, (numFmtIndex + index + Context.OldElementInfos.NumFmtCount).ToString()).ConfigureAwait(false); await NewWriter.WriteAttributeStringAsync(null, "formatCode", null, map.Format).ConfigureAwait(false); await NewWriter.WriteEndElementAsync().ConfigureAwait(false); } @@ -125,7 +120,7 @@ protected override async Task GenerateCellXfAsync() await NewWriter.WriteEndElementAsync().ConfigureAwait(false); const int numFmtIndex = 166; - for (var i = 1; i <= _context.CustomFormatCount; i++) + for (var i = 1; i <= Context.CustomFormatCount; i++) { /* * contentTypes, ZipArchive archive, Encoding encoding) : IDisposable, IAsyncDisposable +internal sealed partial class SheetStyleBuilderContext(Dictionary contentTypes, ZipArchive archive, Encoding encoding) : IDisposable, IAsyncDisposable { private const string EmptyStylesXml = """ @@ -49,13 +47,10 @@ public async Task CreateAsync(SheetStyleElementInfos generatedElementInfos, Canc if (styleEntry is not null) { -#if NET8_0_OR_GREATER var oldStyleXmlStream = await styleEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableStream = oldStyleXmlStream.ConfigureAwait(false); -#else - using var oldStyleXmlStream = styleEntry.Open(); -#endif using var reader = XmlReader.Create(oldStyleXmlStream, XmlReaderHelper.GetXmlReaderSettings(isAsync)); + infos = await ReadSheetStyleElementInfosAsync(reader, cancellationToken).ConfigureAwait(false); } else @@ -88,22 +83,14 @@ public async Task InitializeAsync(SheetStyleElementInfos generatedElementInfos, var xmlReaderSettings = XmlReaderHelper.GetXmlReaderSettings(isAsync); if (_oldStyleXmlZipEntry is not null) { -#if NET8_0_OR_GREATER var oldStyleXmlStream = await _oldStyleXmlZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using (_ = oldStyleXmlStream.ConfigureAwait(false)) -#else - using (var oldStyleXmlStream = _oldStyleXmlZipEntry.Open()) -#endif { using var reader = XmlReader.Create(oldStyleXmlStream, xmlReaderSettings); OldElementInfos = await ReadSheetStyleElementInfosAsync(reader, cancellationToken).ConfigureAwait(false); } -#if NET8_0_OR_GREATER _oldXmlReaderStream = await _oldStyleXmlZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); -#else - _oldXmlReaderStream = _oldStyleXmlZipEntry.Open(); -#endif OldXmlReader = XmlReader.Create(_oldXmlReaderStream, xmlReaderSettings); _newStyleXmlZipEntry = _archive.CreateEntry(ExcelFileNames.Styles + ".temp", CompressionLevel.Fastest); } @@ -116,11 +103,7 @@ public async Task InitializeAsync(SheetStyleElementInfos generatedElementInfos, _newStyleXmlZipEntry = _archive.CreateEntry(ExcelFileNames.Styles, CompressionLevel.Fastest); } -#if NET8_0_OR_GREATER _newXmlWriterStream = await _newStyleXmlZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); -#else - _newXmlWriterStream = _newStyleXmlZipEntry.Open(); -#endif NewXmlWriter = XmlWriter.Create(_newXmlWriterStream, new XmlWriterSettings { Indent = true, Encoding = _encoding, Async = isAsync }); _initialized = true; @@ -137,7 +120,7 @@ public async Task FinalizeAndUpdateZipDictionaryAsync(CancellationToken cancella if (!_initialized) throw new InvalidOperationException("The context has not been initialized."); if (_disposed) - throw new ObjectDisposedException(nameof(SheetStyleBuildContext)); + throw new ObjectDisposedException(nameof(SheetStyleBuilderContext)); if (_finalized) throw new InvalidOperationException("The context has been finalized."); @@ -145,33 +128,19 @@ public async Task FinalizeAndUpdateZipDictionaryAsync(CancellationToken cancella { OldXmlReader?.Dispose(); OldXmlReader = null; -#if NET8_0_OR_GREATER if (_oldXmlReaderStream is not null) { await _oldXmlReaderStream.DisposeAsync().ConfigureAwait(false); } -#else - _oldXmlReaderStream?.Dispose(); -#endif - _oldXmlReaderStream = null; - - _emptyStylesXmlStringReader?.Dispose(); - _emptyStylesXmlStringReader = null; await NewXmlWriter!.FlushAsync().ConfigureAwait(false); -#if NET8_0_OR_GREATER +#if NET await NewXmlWriter.DisposeAsync().ConfigureAwait(false); #else NewXmlWriter.Dispose(); #endif - - NewXmlWriter = null; - -#if NET8_0_OR_GREATER await _newXmlWriterStream!.DisposeAsync().ConfigureAwait(false); -#else - _newXmlWriterStream?.Dispose(); -#endif + NewXmlWriter = null; _newXmlWriterStream = null; if (_oldStyleXmlZipEntry is null) @@ -184,16 +153,12 @@ public async Task FinalizeAndUpdateZipDictionaryAsync(CancellationToken cancella _oldStyleXmlZipEntry = null; var finalStyleXmlZipEntry = _archive.CreateEntry(ExcelFileNames.Styles, CompressionLevel.Fastest); -#if NET8_0_OR_GREATER var tempStream = await _newStyleXmlZipEntry!.OpenAsync(cancellationToken).ConfigureAwait(false); - var newStream = await finalStyleXmlZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); - await using (_ = tempStream.ConfigureAwait(false)) - await using (_= newStream.ConfigureAwait(false)) -#else - using (var tempStream = _newStyleXmlZipEntry!.Open()) - using (var newStream = finalStyleXmlZipEntry.Open()) -#endif + await using (var disposableTempStream = tempStream.ConfigureAwait(false)) { + var newStream = await finalStyleXmlZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); + await using var disposableNewStream = newStream.ConfigureAwait(false); + await tempStream.CopyToAsync(newStream, 4096, cancellationToken).ConfigureAwait(false); } diff --git a/src/MiniExcel.OpenXml/Styles/Builder/SheetStyleBuilderBase.cs b/src/MiniExcel.OpenXml/Styles/Builder/SheetStyleBuilderBase.cs index 534f9737..7984c02d 100644 --- a/src/MiniExcel.OpenXml/Styles/Builder/SheetStyleBuilderBase.cs +++ b/src/MiniExcel.OpenXml/Styles/Builder/SheetStyleBuilderBase.cs @@ -1,12 +1,12 @@ namespace MiniExcelLib.OpenXml.Styles.Builder; -internal abstract partial class SheetStyleBuilderBase(SheetStyleBuildContext context) : ISheetStyleBuilder +internal abstract partial class SheetStyleBuilderBase(SheetStyleBuilderContext context) : ISheetStyleBuilder { - private readonly SheetStyleBuildContext _context = context; + protected readonly SheetStyleBuilderContext Context = context; //todo: these may actually be null if used when the context is not initialized - private XmlReader OldReader => _context.OldXmlReader!; - private XmlWriter NewWriter => _context.NewXmlWriter!; + protected XmlReader OldReader => Context.OldXmlReader!; + protected XmlWriter NewWriter => Context.NewXmlWriter!; private static readonly Dictionary AllElements = new() { @@ -26,7 +26,7 @@ internal abstract partial class SheetStyleBuilderBase(SheetStyleBuildContext con [CreateSyncVersion] public virtual async Task BuildAsync(CancellationToken cancellationToken = default) { - await _context.InitializeAsync(GetGeneratedElementInfos(), cancellationToken).ConfigureAwait(false); + await Context.InitializeAsync(GetGeneratedElementInfos(), cancellationToken).ConfigureAwait(false); while (await OldReader.ReadAsync().ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); @@ -72,7 +72,7 @@ public virtual async Task BuildAsync(CancellationToken cancellationToken = defau } } - await _context.FinalizeAndUpdateZipDictionaryAsync(cancellationToken).ConfigureAwait(false); + await Context.FinalizeAndUpdateZipDictionaryAsync(cancellationToken).ConfigureAwait(false); } protected internal abstract SheetStyleElementInfos GetGeneratedElementInfos(); @@ -106,12 +106,12 @@ protected virtual async Task WriteAttributesAsync(string element, CancellationTo { var value = element switch { - "numFmts" => (_context.OldElementInfos.NumFmtCount + _context.GeneratedElementInfos.NumFmtCount + _context.CustomFormatCount).ToString(), - "fonts" => (_context.OldElementInfos.FontCount + _context.GeneratedElementInfos.FontCount).ToString(), - "fills" => (_context.OldElementInfos.FillCount + _context.GeneratedElementInfos.FillCount).ToString(), - "borders" => (_context.OldElementInfos.BorderCount + _context.GeneratedElementInfos.BorderCount).ToString(), - "cellStyleXfs" => (_context.OldElementInfos.CellStyleXfCount + _context.GeneratedElementInfos.CellStyleXfCount).ToString(), - "cellXfs" => (_context.OldElementInfos.CellXfCount + _context.GeneratedElementInfos.CellXfCount + _context.CustomFormatCount).ToString(), + "numFmts" => (Context.OldElementInfos.NumFmtCount + Context.GeneratedElementInfos.NumFmtCount + Context.CustomFormatCount).ToString(), + "fonts" => (Context.OldElementInfos.FontCount + Context.GeneratedElementInfos.FontCount).ToString(), + "fills" => (Context.OldElementInfos.FillCount + Context.GeneratedElementInfos.FillCount).ToString(), + "borders" => (Context.OldElementInfos.BorderCount + Context.GeneratedElementInfos.BorderCount).ToString(), + "cellStyleXfs" => (Context.OldElementInfos.CellStyleXfCount + Context.GeneratedElementInfos.CellStyleXfCount).ToString(), + "cellXfs" => (Context.OldElementInfos.CellXfCount + Context.GeneratedElementInfos.CellXfCount + Context.CustomFormatCount).ToString(), _ => OldReader.Value }; await NewWriter.WriteStringAsync(value).ConfigureAwait(false); @@ -133,35 +133,35 @@ protected virtual async Task GenerateElementBeforStartElementAsync() if (!AllElements.TryGetValue(OldReader.LocalName, out var elementIndex)) return; - if (!_context.OldElementInfos.ExistsNumFmts && !_context.GeneratedElementInfos.ExistsNumFmts && AllElements["numFmts"] < elementIndex) + if (!Context.OldElementInfos.ExistsNumFmts && !Context.GeneratedElementInfos.ExistsNumFmts && AllElements["numFmts"] < elementIndex) { await GenerateNumFmtsAsync().ConfigureAwait(false); - _context.GeneratedElementInfos.ExistsNumFmts = true; + Context.GeneratedElementInfos.ExistsNumFmts = true; } - else if (!_context.OldElementInfos.ExistsFonts && !_context.GeneratedElementInfos.ExistsFonts && AllElements["fonts"] < elementIndex) + else if (!Context.OldElementInfos.ExistsFonts && !Context.GeneratedElementInfos.ExistsFonts && AllElements["fonts"] < elementIndex) { await GenerateFontsAsync().ConfigureAwait(false); - _context.GeneratedElementInfos.ExistsFonts = true; + Context.GeneratedElementInfos.ExistsFonts = true; } - else if (!_context.OldElementInfos.ExistsFills && !_context.GeneratedElementInfos.ExistsFills && AllElements["fills"] < elementIndex) + else if (!Context.OldElementInfos.ExistsFills && !Context.GeneratedElementInfos.ExistsFills && AllElements["fills"] < elementIndex) { await GenerateFillsAsync().ConfigureAwait(false); - _context.GeneratedElementInfos.ExistsFills = true; + Context.GeneratedElementInfos.ExistsFills = true; } - else if (!_context.OldElementInfos.ExistsBorders && !_context.GeneratedElementInfos.ExistsBorders && AllElements["borders"] < elementIndex) + else if (!Context.OldElementInfos.ExistsBorders && !Context.GeneratedElementInfos.ExistsBorders && AllElements["borders"] < elementIndex) { await GenerateBordersAsync().ConfigureAwait(false); - _context.GeneratedElementInfos.ExistsBorders = true; + Context.GeneratedElementInfos.ExistsBorders = true; } - else if (!_context.OldElementInfos.ExistsCellStyleXfs && !_context.GeneratedElementInfos.ExistsCellStyleXfs && AllElements["cellStyleXfs"] < elementIndex) + else if (!Context.OldElementInfos.ExistsCellStyleXfs && !Context.GeneratedElementInfos.ExistsCellStyleXfs && AllElements["cellStyleXfs"] < elementIndex) { await GenerateCellStyleXfsAsync().ConfigureAwait(false); - _context.GeneratedElementInfos.ExistsCellStyleXfs = true; + Context.GeneratedElementInfos.ExistsCellStyleXfs = true; } - else if (!_context.OldElementInfos.ExistsCellXfs && !_context.GeneratedElementInfos.ExistsCellXfs && AllElements["cellXfs"] < elementIndex) + else if (!Context.OldElementInfos.ExistsCellXfs && !Context.GeneratedElementInfos.ExistsCellXfs && AllElements["cellXfs"] < elementIndex) { await GenerateCellXfsAsync().ConfigureAwait(false); - _context.GeneratedElementInfos.ExistsCellXfs = true; + Context.GeneratedElementInfos.ExistsCellXfs = true; } } @@ -170,7 +170,7 @@ protected virtual async Task GenerateElementBeforEndElementAsync() { switch (OldReader.LocalName) { - case "styleSheet" when !_context.OldElementInfos.ExistsNumFmts && !_context.GeneratedElementInfos.ExistsNumFmts: + case "styleSheet" when !Context.OldElementInfos.ExistsNumFmts && !Context.GeneratedElementInfos.ExistsNumFmts: await GenerateNumFmtsAsync().ConfigureAwait(false); break; case "numFmts": @@ -198,11 +198,11 @@ protected virtual async Task GenerateElementBeforEndElementAsync() protected virtual async Task GenerateNumFmtsAsync() { await NewWriter.WriteStartElementAsync(OldReader.Prefix, "numFmts", OldReader.NamespaceURI).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "count", null, (_context.OldElementInfos.NumFmtCount + _context.GeneratedElementInfos.NumFmtCount + _context.CustomFormatCount).ToString()).ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "count", null, (Context.OldElementInfos.NumFmtCount + Context.GeneratedElementInfos.NumFmtCount + Context.CustomFormatCount).ToString()).ConfigureAwait(false); await GenerateNumFmtAsync().ConfigureAwait(false); await NewWriter.WriteFullEndElementAsync().ConfigureAwait(false); - if (!_context.OldElementInfos.ExistsFonts) + if (!Context.OldElementInfos.ExistsFonts) { await GenerateFontsAsync().ConfigureAwait(false); } @@ -215,11 +215,11 @@ protected virtual async Task GenerateNumFmtsAsync() protected virtual async Task GenerateFontsAsync() { await NewWriter.WriteStartElementAsync(OldReader.Prefix, "fonts", OldReader.NamespaceURI).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "count", null, (_context.OldElementInfos.FontCount + _context.GeneratedElementInfos.FontCount).ToString()).ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "count", null, (Context.OldElementInfos.FontCount + Context.GeneratedElementInfos.FontCount).ToString()).ConfigureAwait(false); await GenerateFontAsync().ConfigureAwait(false); await NewWriter.WriteFullEndElementAsync().ConfigureAwait(false); - if (!_context.OldElementInfos.ExistsFills) + if (!Context.OldElementInfos.ExistsFills) { await GenerateFillsAsync().ConfigureAwait(false); } @@ -232,11 +232,11 @@ protected virtual async Task GenerateFontsAsync() protected virtual async Task GenerateFillsAsync() { await NewWriter.WriteStartElementAsync(OldReader.Prefix, "fills", OldReader.NamespaceURI).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "count", null, (_context.OldElementInfos.FillCount + _context.GeneratedElementInfos.FillCount).ToString()).ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "count", null, (Context.OldElementInfos.FillCount + Context.GeneratedElementInfos.FillCount).ToString()).ConfigureAwait(false); await GenerateFillAsync().ConfigureAwait(false); await NewWriter.WriteFullEndElementAsync().ConfigureAwait(false); - if (!_context.OldElementInfos.ExistsBorders) + if (!Context.OldElementInfos.ExistsBorders) { await GenerateBordersAsync().ConfigureAwait(false); } @@ -249,11 +249,11 @@ protected virtual async Task GenerateFillsAsync() protected virtual async Task GenerateBordersAsync() { await NewWriter.WriteStartElementAsync(OldReader.Prefix, "borders", OldReader.NamespaceURI).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "count", null, (_context.OldElementInfos.BorderCount + _context.GeneratedElementInfos.BorderCount).ToString()).ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "count", null, (Context.OldElementInfos.BorderCount + Context.GeneratedElementInfos.BorderCount).ToString()).ConfigureAwait(false); await GenerateBorderAsync().ConfigureAwait(false); await NewWriter.WriteFullEndElementAsync().ConfigureAwait(false); - if (!_context.OldElementInfos.ExistsCellStyleXfs) + if (!Context.OldElementInfos.ExistsCellStyleXfs) { await GenerateCellStyleXfsAsync().ConfigureAwait(false); } @@ -266,11 +266,11 @@ protected virtual async Task GenerateBordersAsync() protected virtual async Task GenerateCellStyleXfsAsync() { await NewWriter.WriteStartElementAsync(OldReader.Prefix, "cellStyleXfs", OldReader.NamespaceURI).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "count", null, (_context.OldElementInfos.CellStyleXfCount + _context.GeneratedElementInfos.CellStyleXfCount).ToString()).ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "count", null, (Context.OldElementInfos.CellStyleXfCount + Context.GeneratedElementInfos.CellStyleXfCount).ToString()).ConfigureAwait(false); await GenerateCellStyleXfAsync().ConfigureAwait(false); await NewWriter.WriteFullEndElementAsync().ConfigureAwait(false); - if (!_context.OldElementInfos.ExistsCellXfs) + if (!Context.OldElementInfos.ExistsCellXfs) { await GenerateCellXfsAsync().ConfigureAwait(false); } @@ -283,7 +283,7 @@ protected virtual async Task GenerateCellStyleXfsAsync() protected virtual async Task GenerateCellXfsAsync() { await NewWriter.WriteStartElementAsync(OldReader.Prefix, "cellXfs", OldReader.NamespaceURI).ConfigureAwait(false); - await NewWriter.WriteAttributeStringAsync(null, "count", null, (_context.OldElementInfos.CellXfCount + _context.GeneratedElementInfos.CellXfCount + _context.CustomFormatCount).ToString()).ConfigureAwait(false); + await NewWriter.WriteAttributeStringAsync(null, "count", null, (Context.OldElementInfos.CellXfCount + Context.GeneratedElementInfos.CellXfCount + Context.CustomFormatCount).ToString()).ConfigureAwait(false); await GenerateCellXfAsync().ConfigureAwait(false); await NewWriter.WriteFullEndElementAsync().ConfigureAwait(false); } diff --git a/src/MiniExcel.OpenXml/Styles/Builder/SheetStyleFormatsCache.cs b/src/MiniExcel.OpenXml/Styles/Builder/SheetStyleFormatsCache.cs index e7ec1ca9..2feb550b 100644 --- a/src/MiniExcel.OpenXml/Styles/Builder/SheetStyleFormatsCache.cs +++ b/src/MiniExcel.OpenXml/Styles/Builder/SheetStyleFormatsCache.cs @@ -1,5 +1,6 @@ namespace MiniExcelLib.OpenXml.Styles.Builder; +// todo: find a way to make it compatible with SharedStringsDiskCache internal class SheetStyleFormatsCache { private readonly Dictionary _formatMappings = []; diff --git a/src/MiniExcel.OpenXml/Styles/OpenXmlHeaderStyle.cs b/src/MiniExcel.OpenXml/Styles/OpenXmlHeaderStyle.cs index 3f0b14b3..95ea3f01 100644 --- a/src/MiniExcel.OpenXml/Styles/OpenXmlHeaderStyle.cs +++ b/src/MiniExcel.OpenXml/Styles/OpenXmlHeaderStyle.cs @@ -1,5 +1,4 @@ using System.Drawing; -using MiniExcelLib.Core.Enums; namespace MiniExcelLib.OpenXml.Styles; diff --git a/src/MiniExcel.OpenXml/Styles/OpenXmlStyleOptions.cs b/src/MiniExcel.OpenXml/Styles/OpenXmlStyleOptions.cs index b81762ed..c4c232cb 100644 --- a/src/MiniExcel.OpenXml/Styles/OpenXmlStyleOptions.cs +++ b/src/MiniExcel.OpenXml/Styles/OpenXmlStyleOptions.cs @@ -1,7 +1,5 @@ namespace MiniExcelLib.OpenXml.Styles; -using MiniExcelLib.Core.Enums; - public class OpenXmlStyleOptions { public bool WrapCellContents { get; set; } diff --git a/src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs b/src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs index 20f51a19..70937eb3 100644 --- a/src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs +++ b/src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs @@ -1,4 +1,3 @@ -using MiniExcelLib.OpenXml.Constants; using XmlReaderHelper = MiniExcelLib.OpenXml.Utils.XmlReaderHelper; namespace MiniExcelLib.OpenXml.Styles; @@ -13,7 +12,7 @@ internal class OpenXmlStyles public OpenXmlStyles(OpenXmlZip zip) { - using var reader = zip.GetXmlReader("xl/styles.xml"); + using var reader = zip.GetXmlReader(ExcelFileNames.Styles); if (reader is null) throw new InvalidDataException("The OpenXml styles could not be found, the file might be malformed."); @@ -86,12 +85,7 @@ public OpenXmlStyles(OpenXmlZip zip) type = typeof(DateTime?); } -#if NETCOREAPP2_0_OR_GREATER _customFormats.TryAdd(numFmtId, new NumberFormatString(formatCode, type)); -#else - if (!_customFormats.ContainsKey(numFmtId)) - _customFormats.Add(numFmtId, new NumberFormatString(formatCode, type)); -#endif reader.Skip(); } else if (!reader.SkipContent()) diff --git a/src/MiniExcel.OpenXml/Styles/SheetStyleElementInfos.cs b/src/MiniExcel.OpenXml/Styles/SheetStyleElementInfos.cs index db6bc188..e89eb16e 100644 --- a/src/MiniExcel.OpenXml/Styles/SheetStyleElementInfos.cs +++ b/src/MiniExcel.OpenXml/Styles/SheetStyleElementInfos.cs @@ -1,6 +1,6 @@ namespace MiniExcelLib.OpenXml.Styles; -public class SheetStyleElementInfos +internal class SheetStyleElementInfos { public bool ExistsNumFmts { get; set; } public int NumFmtCount { get; set; } @@ -14,4 +14,4 @@ public class SheetStyleElementInfos public int CellStyleXfCount { get; set; } public bool ExistsCellXfs { get; set; } public int CellXfCount { get; set; } -} \ No newline at end of file +} diff --git a/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.Impl.cs b/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.Impl.cs index 859654d0..fa170553 100644 --- a/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.Impl.cs +++ b/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.Impl.cs @@ -1,8 +1,3 @@ -using MiniExcelLib.Core.Attributes; -using System.ComponentModel; -using System.Xml.Linq; -using MiniExcelLib.OpenXml.Constants; - namespace MiniExcelLib.OpenXml.Templates; internal partial class OpenXmlTemplate @@ -15,17 +10,8 @@ internal partial class OpenXmlTemplate Async = true #endif }; - - private static readonly XmlWriterSettings FragXmlWriterSettings = new() - { - OmitXmlDeclaration = true, - ConformanceLevel = ConformanceLevel.Fragment, -#if !SYNC_ONLY - Async = true -#endif - }; -#if NET8_0_OR_GREATER +#if NET [GeneratedRegex("(?<={{).*?(?=}})")] private static partial Regex ExpressionRegex(); private static readonly Regex IsExpressionRegex = ExpressionRegex(); [GeneratedRegex("([A-Z]+)([0-9]+)")] private static partial Regex CellRegexImpl(); @@ -37,7 +23,7 @@ internal partial class OpenXmlTemplate [GeneratedRegex(@"<(?:x:)?v>\s*")] private static partial Regex EmptyVTagRegexImpl(); private static readonly Regex EmptyVTagRegex = EmptyVTagRegexImpl(); #else - private static readonly Regex IsExpressionRegex = new("(?<={{).*?(?=}})"); + private static readonly Regex IsExpressionRegex = new("(?<={{).*?(?=}})", RegexOptions.Compiled); private static readonly Regex CellRegex = new("([A-Z]+)([0-9]+)", RegexOptions.Compiled); private static readonly Regex TemplateRegex = new(@"\{\{(.*?)\}\}", RegexOptions.Compiled); private static readonly Regex NonTemplateRegex = new(@".*?\{\{.*?\}\}.*?", RegexOptions.Compiled); @@ -53,13 +39,8 @@ internal partial class OpenXmlTemplate [CreateSyncVersion] private async Task GenerateSheetByUpdateModeAsync(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream, IDictionary inputMaps, IDictionary sharedStrings, bool mergeCells = false, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var doc = await XDocument.LoadAsync(sheetStream, LoadOptions.None, cancellationToken).ConfigureAwait(false); await sheetStream.DisposeAsync().ConfigureAwait(false); -#else - var doc = XDocument.Load(sheetStream); - sheetStream.Dispose(); -#endif // we can't update ZipArchiveEntry directly, so we delete the original entry and recreate it sheetZipEntry.Delete(); @@ -73,7 +54,7 @@ private async Task GenerateSheetByUpdateModeAsync(ZipArchiveEntry sheetZipEntry, GetMergeCells(worksheet); UpdateDimensionAndGetRowsInfo(inputMaps, worksheet, rows, !mergeCells); -#if NET8_0_OR_GREATER +#if NET var writer = XmlWriter.Create(stream, DocXmlWriterSettings); await using var disposableWriter = writer.ConfigureAwait(false); #else @@ -86,14 +67,10 @@ private async Task GenerateSheetByUpdateModeAsync(ZipArchiveEntry sheetZipEntry, [CreateSyncVersion] private async Task GenerateSheetByCreateModeAsync(ZipArchiveEntry templateSheetZipEntry, Stream outputZipSheetEntryStream, IDictionary inputMaps, IDictionary sharedStrings, bool mergeCells = false, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var newTemplateStream = await templateSheetZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableNewTemplateStream = newTemplateStream.ConfigureAwait(false); var doc = await XDocument.LoadAsync(newTemplateStream, LoadOptions.None, cancellationToken).ConfigureAwait(false); -#else - using var newTemplateStream = templateSheetZipEntry.Open(); - var doc = XDocument.Load(newTemplateStream); -#endif + var worksheet = doc.Element(SpreadsheetNs + "worksheet"); var prefix = worksheet?.GetPrefixOfNamespace(SpreadsheetNs); if (!string.IsNullOrEmpty(prefix)) @@ -111,7 +88,7 @@ private async Task GenerateSheetByCreateModeAsync(ZipArchiveEntry templateSheetZ GetMergeCells(worksheet); UpdateDimensionAndGetRowsInfo(inputMaps, worksheet, rows, !mergeCells); -#if NET8_0_OR_GREATER +#if NET var writer = XmlWriter.Create(outputZipSheetEntryStream, DocXmlWriterSettings); await using var disposableWriter = writer.ConfigureAwait(false); #else @@ -236,7 +213,7 @@ private async Task WriteSheetXmlAsync(XmlWriter writer, XElement worksheet, XEle foreach (var beforeElement in beforeSheetData) { -#if NET8_0_OR_GREATER +#if NET await beforeElement.WriteToAsync(writer, cancellationToken).ConfigureAwait(false); #else beforeElement.WriteTo(writer); @@ -493,7 +470,7 @@ var s when s.StartsWith("@header") => SpecialCellType.Header, foreach (var afterElement in afterSheetData) { -#if NET8_0_OR_GREATER +#if NET await afterElement.WriteToAsync(writer, cancellationToken).ConfigureAwait(false); #else afterElement.WriteTo(writer); @@ -633,11 +610,8 @@ private async Task GenerateCellValuesAsync( else { var replacements = new Dictionary(); -#if NET8_0_OR_GREATER string MatchDelegate(Match x) => replacements.GetValueOrDefault(x.Groups[1].Value, ""); -#else - string MatchDelegate(Match x) => replacements.TryGetValue(x.Groups[1].Value, out var repl) ? repl : ""; -#endif + foreach (var prop in rowInfo.PropsMap) { var propInfo = prop.Value.PropertyInfo; diff --git a/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.MergeCells.cs b/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.MergeCells.cs index 5d84f3b4..1ff7f05d 100644 --- a/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.MergeCells.cs +++ b/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.MergeCells.cs @@ -5,24 +5,18 @@ internal partial class OpenXmlTemplate [CreateSyncVersion] public async Task MergeSameCellsAsync(string path, CancellationToken cancellationToken = default) { -#if NETSTANDARD2_0 - using var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); -#else var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); await using var disposableStream = stream.ConfigureAwait(false); -#endif + await MergeSameCellsImplAsync(stream, cancellationToken).ConfigureAwait(false); } [CreateSyncVersion] public async Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken cancellationToken = default) { -#if NETSTANDARD2_0 - using var stream = new MemoryStream(fileInBytes); -#else var stream = new MemoryStream(fileInBytes); await using var disposableStream = stream.ConfigureAwait(false); -#endif + await MergeSameCellsImplAsync(stream, cancellationToken).ConfigureAwait(false); } @@ -30,7 +24,7 @@ public async Task MergeSameCellsAsync(byte[] fileInBytes, CancellationToken canc private async Task MergeSameCellsImplAsync(Stream stream, CancellationToken cancellationToken = default) { await stream.CopyToAsync(_outputFileStream -#if NET8_0_OR_GREATER +#if NET , cancellationToken #endif ).ConfigureAwait(false); @@ -44,8 +38,7 @@ await stream.CopyToAsync(_outputFileStream //read all xlsx sheets var sheets = archive.ZipFile.Entries.Where(w => - w.FullName.StartsWith("xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase) || - w.FullName.StartsWith("/xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase) + w.FullName.TrimStart('/').StartsWith(ExcelFileNames.WorksheetBase, StringComparison.OrdinalIgnoreCase) ).ToList(); foreach (var sheet in sheets) @@ -58,16 +51,11 @@ await stream.CopyToAsync(_outputFileStream var entry = archive.ZipFile.CreateEntry(sheet.FullName); -#if NET8_0_OR_GREATER var sheetStream = await sheet.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableSheetStream = sheetStream.ConfigureAwait(false); var zipStream = await entry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableZipStream = zipStream.ConfigureAwait(false); -#else - using var sheetStream = sheet.Open(); - using var zipStream = entry.Open(); -#endif await GenerateSheetByUpdateModeAsync(sheet, zipStream, sheetStream, new Dictionary(), sharedStrings, mergeCells: true, cancellationToken).ConfigureAwait(false); } diff --git a/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.cs b/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.cs index eb52eaa3..d14b36b5 100644 --- a/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.cs +++ b/src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.cs @@ -1,4 +1,3 @@ -using MiniExcelLib.Core; using CalcChainHelper = MiniExcelLib.OpenXml.Utils.CalcChainHelper; namespace MiniExcelLib.OpenXml.Templates; @@ -20,24 +19,18 @@ internal OpenXmlTemplate(Stream stream, IMiniExcelConfiguration? configuration, [CreateSyncVersion] public async Task SaveAsByTemplateAsync(string templatePath, object value, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = File.Open(templatePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = File.Open(templatePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); -#endif + await SaveAsByTemplateAsync(stream, value, cancellationToken).ConfigureAwait(false); } [CreateSyncVersion] public async Task SaveAsByTemplateAsync(byte[] templateBytes, object value, CancellationToken cancellationToken = default) { -#if NET8_0_OR_GREATER var stream = new MemoryStream(templateBytes); await using var disposableStream = stream.ConfigureAwait(false); -#else - using var stream = new MemoryStream(templateBytes); -#endif + await SaveAsByTemplateAsync(stream, value, cancellationToken).ConfigureAwait(false); } @@ -80,26 +73,24 @@ public async Task SaveAsByTemplateAsync(Stream templateStream, object value, Can foreach (var entry in originalArchive.Entries) { var entryName = entry.FullName.TrimStart('/'); - if (entryName.StartsWith("xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase) || entryName.Equals("xl/calcChain.xml")) + if (entryName.StartsWith(ExcelFileNames.WorksheetBase, StringComparison.OrdinalIgnoreCase) || + entryName.Equals(ExcelFileNames.CalcChain, StringComparison.OrdinalIgnoreCase)) + { continue; - + } + // Create a new entry in the new archive with the same name var newEntry = outputFileArchive.ZipFile.CreateEntry(entry.FullName); // Copy the content of the original entry to the new entry -#if NET8_0_OR_GREATER var originalEntryStream = await entry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableEntryStream = originalEntryStream.ConfigureAwait(false); var newEntryStream = await newEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableNewEntryStream = newEntryStream.ConfigureAwait(false); -#else - using var originalEntryStream = entry.Open(); - using var newEntryStream = newEntry.Open(); -#endif await originalEntryStream.CopyToAsync(newEntryStream -#if NET8_0_OR_GREATER +#if NET , cancellationToken #endif ).ConfigureAwait(false); @@ -113,7 +104,7 @@ await originalEntryStream.CopyToAsync(newEntryStream var templateSheets = templateReader.Archive.ZipFile.Entries .Where(entry => entry.FullName .TrimStart('/') - .StartsWith("xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase)); + .StartsWith(ExcelFileNames.WorksheetBase, StringComparison.OrdinalIgnoreCase)); int sheetIdx = 0; foreach (var templateSheet in templateSheets) @@ -128,12 +119,9 @@ await originalEntryStream.CopyToAsync(newEntryStream var inputValues = _inputValueExtractor.ToValueDictionary(value); var outputZipEntry = outputFileArchive.ZipFile.CreateEntry(templateFullName); -#if NET8_0_OR_GREATER var outputZipSheetEntryStream = await outputZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableSheetEntryStream = outputZipSheetEntryStream.ConfigureAwait(false); -#else - using var outputZipSheetEntryStream = outputZipEntry.Open(); -#endif + await GenerateSheetByCreateModeAsync(templateSheet, outputZipSheetEntryStream, inputValues, templateSharedStrings, cancellationToken: cancellationToken).ConfigureAwait(false); //doc.Save(zipStream); //don't do it because: https://user-images.githubusercontent.com/12729184/114361127-61a5d100-9ba8-11eb-9bb9-34f076ee28a2.png @@ -144,43 +132,34 @@ await originalEntryStream.CopyToAsync(newEntryStream } // create mode we need to not create first then create here - var calcChain = outputFileArchive.EntryCollection.FirstOrDefault(e => e.FullName.Contains("xl/calcChain.xml")); + var calcChain = outputFileArchive.EntryCollection.FirstOrDefault(e + => e.FullName.TrimStart('/').Equals(ExcelFileNames.CalcChain, StringComparison.OrdinalIgnoreCase)); + if (calcChain is not null) { - var calcChainPathName = calcChain.FullName; - //calcChain.Delete(); - - var calcChainEntry = outputFileArchive.ZipFile.CreateEntry(calcChainPathName); -#if NET8_0_OR_GREATER + var calcChainEntry = outputFileArchive.ZipFile.CreateEntry(calcChain.FullName); var calcChainStream = await calcChainEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableChainEntryStream = calcChainStream.ConfigureAwait(false); -#else - using var calcChainStream = calcChainEntry.Open(); -#endif + await CalcChainHelper.GenerateCalcChainSheetAsync(calcChainStream, _calcChainContent.ToString(), cancellationToken).ConfigureAwait(false); } else { foreach (var entry in originalArchive.Entries) { - if (entry.FullName.Contains("xl/calcChain.xml")) + if (entry.FullName.TrimStart('/').Equals(ExcelFileNames.CalcChain, StringComparison.OrdinalIgnoreCase)) { var newEntry = outputFileArchive.ZipFile.CreateEntry(entry.FullName); // Copy the content of the original entry to the new entry -#if NET8_0_OR_GREATER var originalEntryStream = await entry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableEntryStream = originalEntryStream.ConfigureAwait(false); var newEntryStream = await newEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableNewEntryStream = newEntryStream.ConfigureAwait(false); -#else - using var originalEntryStream = entry.Open(); - using var newEntryStream = newEntry.Open(); -#endif await originalEntryStream.CopyToAsync(newEntryStream -#if NET8_0_OR_GREATER +#if NET , cancellationToken #endif ).ConfigureAwait(false); diff --git a/src/MiniExcel.OpenXml/Templates/OpenXmlTemplateUtils.cs b/src/MiniExcel.OpenXml/Templates/OpenXmlTemplateUtils.cs index b0ffcc62..0d5d0c7a 100644 --- a/src/MiniExcel.OpenXml/Templates/OpenXmlTemplateUtils.cs +++ b/src/MiniExcel.OpenXml/Templates/OpenXmlTemplateUtils.cs @@ -1,6 +1,4 @@ -using System.Xml.Linq; - -namespace MiniExcelLib.OpenXml.Templates; +namespace MiniExcelLib.OpenXml.Templates; internal class XRowInfo { diff --git a/src/MiniExcel.OpenXml/Utils/CalcChainHelper.cs b/src/MiniExcel.OpenXml/Utils/CalcChainHelper.cs index f58fadfc..db076575 100644 --- a/src/MiniExcel.OpenXml/Utils/CalcChainHelper.cs +++ b/src/MiniExcel.OpenXml/Utils/CalcChainHelper.cs @@ -24,13 +24,13 @@ public static async Task GenerateCalcChainSheetAsync(Stream calcChainStream, str { var content = $"{calcChainContent}"; -#if NET8_0_OR_GREATER +#if NET var writer = new StreamWriter(calcChainStream, Encoding.UTF8); await using var disposableWriter = writer.ConfigureAwait(false); await writer.WriteAsync(content.AsMemory(), cancellationToken).ConfigureAwait(false); - #else +#else using var writer = new StreamWriter(calcChainStream, Encoding.UTF8); await writer.WriteAsync(content).ConfigureAwait(false); - #endif +#endif } } diff --git a/src/MiniExcel.OpenXml/Utils/MiniExcelPropertyHelper.cs b/src/MiniExcel.OpenXml/Utils/MiniExcelPropertyHelper.cs index 58f73568..c44e4fb6 100644 --- a/src/MiniExcel.OpenXml/Utils/MiniExcelPropertyHelper.cs +++ b/src/MiniExcel.OpenXml/Utils/MiniExcelPropertyHelper.cs @@ -1,5 +1,3 @@ -using MiniExcelLib.Core; - namespace MiniExcelLib.OpenXml.Utils; internal static class MiniExcelPropertyHelper diff --git a/src/MiniExcel.OpenXml/Utils/XmlReaderHelper.cs b/src/MiniExcel.OpenXml/Utils/XmlReaderHelper.cs index 0373d302..2266bfb8 100644 --- a/src/MiniExcel.OpenXml/Utils/XmlReaderHelper.cs +++ b/src/MiniExcel.OpenXml/Utils/XmlReaderHelper.cs @@ -1,5 +1,3 @@ -using MiniExcelLib.OpenXml.Constants; - namespace MiniExcelLib.OpenXml.Utils; internal static partial class XmlReaderHelper @@ -13,7 +11,7 @@ public static async Task ReadFirstContentAsync(this XmlReader reader, Canc if (reader.IsEmptyElement) { await reader.ReadAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); @@ -21,13 +19,13 @@ await reader.ReadAsync() } await reader.MoveToContentAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); await reader.ReadAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); @@ -41,7 +39,7 @@ public static async Task SkipContentAsync(this XmlReader reader, Cancellat if (reader.NodeType == XmlNodeType.EndElement) { await reader.ReadAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); @@ -49,7 +47,7 @@ await reader.ReadAsync() } await reader.SkipAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false); @@ -95,7 +93,7 @@ public static async Task ReadStringItemAsync(this XmlReader reader, Canc { // There are multiple in a . Concatenate within an . result.Append(await reader.ReadElementContentAsStringAsync() -#if NET6_0_OR_GREATER +#if NET .WaitAsync(cancellationToken) #endif .ConfigureAwait(false)); @@ -126,8 +124,8 @@ private static async Task ReadRichTextRunAsync(this XmlReader reader, Ca if (reader.IsStartElement("t", Ns)) { result.Append(await reader.ReadElementContentAsStringAsync() -#if NET6_0_OR_GREATER - .WaitAsync(cancellationToken) +#if NET + .WaitAsync(cancellationToken) #endif .ConfigureAwait(false)); } diff --git a/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.CopyInsert.cs b/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.CopyInsert.cs index 7839b7c8..24b0f3aa 100644 --- a/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.CopyInsert.cs +++ b/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.CopyInsert.cs @@ -1,7 +1,3 @@ -using System.ComponentModel; -using System.Xml.Linq; -using MiniExcelLib.Core; -using MiniExcelLib.OpenXml.Constants; using MiniExcelLib.OpenXml.Styles.Builder; namespace MiniExcelLib.OpenXml.Writer; @@ -71,8 +67,8 @@ public async Task CopyAndInsertAsync(bool overwriteSheet = false, IProgress var sheetStylesBuilderUtils = await CopySheetStylesAndGetBuilderUtilsAsync(cancellationToken).ConfigureAwait(false); await using var disposableSheetStylesBuilderUtils = sheetStylesBuilderUtils.ConfigureAwait(false); - await _sheetStyleBuildContext.DisposeAsync().ConfigureAwait(false); - _sheetStyleBuildContext = sheetStylesBuilderUtils.SheetStyleBuildContext; + await _sheetStyleBuilderContext.DisposeAsync().ConfigureAwait(false); + _sheetStyleBuilderContext = sheetStylesBuilderUtils.SheetStyleBuilderContext; var sharedStringsEntry = _oldArchive.GetEntry(ExcelFileNames.SharedStrings); if (sharedStringsEntry is not null) @@ -101,8 +97,8 @@ public async Task CopyAndInsertAsync(bool overwriteSheet = false, IProgress entriesToIgnoreOnCopy.AddRange([ ExcelFileNames.Worksheet(_currentSheetIndex), ExcelFileNames.SheetRels(_currentSheetIndex), - ExcelFileNames.Drawing(_currentSheetIndex - 1), - ExcelFileNames.DrawingRels(_currentSheetIndex - 1) + ExcelFileNames.Drawing(_currentSheetIndex), + ExcelFileNames.DrawingRels(_currentSheetIndex) ]); } @@ -116,15 +112,10 @@ public async Task CopyAndInsertAsync(bool overwriteSheet = false, IProgress { var newStylesEntry = _archive.CreateEntry(ExcelFileNames.Styles, CompressionLevel.Fastest); var newStylesEntryStream = await newStylesEntry.OpenAsync(cancellationToken).ConfigureAwait(false); - var tempStylesEntryStream = await tempStylesEntry.OpenAsync(cancellationToken).ConfigureAwait(false); - -#if NET8_0_OR_GREATER await using var disposableNewStylesEntryStream = newStylesEntryStream.ConfigureAwait(false); + + var tempStylesEntryStream = await tempStylesEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableTempStylesEntryStream = tempStylesEntryStream.ConfigureAwait(false); -#else - using var disposableNewStylesEntryStream = newStylesEntryStream; - using var disposableTempStylesEntryStream = tempStylesEntryStream; -#endif await tempStylesEntryStream.CopyToAsync(newStylesEntryStream, 81920, cancellationToken).ConfigureAwait(false); await newStylesEntryStream.FlushAsync(cancellationToken).ConfigureAwait(false); @@ -132,8 +123,8 @@ public async Task CopyAndInsertAsync(bool overwriteSheet = false, IProgress await AddFilesToZipAsync(cancellationToken).ConfigureAwait(false); await GenerateSharedStringsAsync(cancellationToken).ConfigureAwait(false); - await GenerateDrawingRelXmlAsync(_currentSheetIndex - 1, cancellationToken).ConfigureAwait(false); - await GenerateDrawingXmlAsync(_currentSheetIndex - 1, cancellationToken).ConfigureAwait(false); + await GenerateDrawingRelXmlAsync(_currentSheetIndex, cancellationToken).ConfigureAwait(false); + await GenerateDrawingXmlAsync(_currentSheetIndex, cancellationToken).ConfigureAwait(false); await CreateZipEntryAsync( ExcelFileNames.SheetRels(_currentSheetIndex), @@ -184,10 +175,10 @@ private async Task CopySheetStylesAndGetBuilderUtil backingStream.Seek(0, SeekOrigin.Begin); var copiedArchive = await ZipArchive.CreateAsync(backingStream, ZipArchiveMode.Update, true, Utf8WithBom, cancellationToken).ConfigureAwait(false); - SheetStyleBuildContext? oldStylesContext = null; + SheetStyleBuilderContext? oldStylesContext = null; try { - oldStylesContext = new SheetStyleBuildContext(_zipContentsMap, copiedArchive, Utf8WithBom); + oldStylesContext = new SheetStyleBuilderContext(_zipContentsMap, copiedArchive, Utf8WithBom); SheetStyleBuilderBase builder = _configuration.TableStyles switch { TableStyles.None => new MinimalSheetStyleBuilder(oldStylesContext), @@ -218,16 +209,11 @@ private async Task CopyEntryAsync(ZipArchiveEntry entry, CancellationToken cance { var newEntry = _archive.CreateEntry(entry.FullName, CompressionLevel.Fastest); -#if NET8_0_OR_GREATER var oldEntryStream = await _oldArchive!.GetEntry(entry.FullName)!.OpenAsync(cancellationToken).ConfigureAwait(false); await using var oldDisposableSheetStream = oldEntryStream.ConfigureAwait(false); var newEntryStream = await newEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var newDisposableSheetStream = newEntryStream.ConfigureAwait(false); -#else - using var oldEntryStream = await _oldArchive!.GetEntry(entry.FullName)!.OpenAsync(cancellationToken).ConfigureAwait(false); - using var newEntryStream = await newEntry.OpenAsync(cancellationToken).ConfigureAwait(false); -#endif await oldEntryStream.CopyToAsync(newEntryStream, 81920, cancellationToken).ConfigureAwait(false); await newEntryStream.FlushAsync(cancellationToken).ConfigureAwait(false); @@ -243,15 +229,10 @@ private async Task CopyAndUpdateContentTypesAsync(CancellationToken cancellation return; } -#if NET8_0_OR_GREATER var stream = await contentTypesZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableStream = stream.ConfigureAwait(false); - var doc = await XDocument.LoadAsync(stream, LoadOptions.None, cancellationToken).ConfigureAwait(false); -#else - using var stream = contentTypesZipEntry.Open(); - var doc = XDocument.Load(stream); -#endif + var doc = await XDocument.LoadAsync(stream, LoadOptions.None, cancellationToken).ConfigureAwait(false); var ns = doc.Root!.GetDefaultNamespace(); var typesElement = doc.Descendants(ns + "Types").Single(); @@ -276,43 +257,35 @@ private async Task CopyAndUpdateContentTypesAsync(CancellationToken cancellation var contentTypesEntry = _archive.CreateEntry(ExcelFileNames.ContentTypes, CompressionLevel.Fastest); var contentTypesEntryStream = await contentTypesEntry.OpenAsync(cancellationToken).ConfigureAwait(false); -#if NET8_0_OR_GREATER await using var disposableContetTypesEntryStream = contentTypesEntryStream.ConfigureAwait(false); + await doc.SaveAsync(contentTypesEntryStream, SaveOptions.None, cancellationToken).ConfigureAwait(false); -#else - using var disposableContetTypesEntryStream = contentTypesEntryStream; - doc.Save(contentTypesEntryStream); -#endif } - private class TempSheetStylesBuilderUtils(Stream backingStream, ZipArchive archive, SheetStyleBuildContext sheetStyleBuildContext, ISheetStyleBuilder sheetStyleBuilder) : IDisposable, IAsyncDisposable + private class TempSheetStylesBuilderUtils(Stream backingStream, ZipArchive archive, SheetStyleBuilderContext sheetStyleBuilderContext, ISheetStyleBuilder sheetStyleBuilder) : IDisposable, IAsyncDisposable { private readonly Stream _backingStream = backingStream; public ZipArchive Archive { get; } = archive; public ISheetStyleBuilder SheetStyleBuilder { get; } = sheetStyleBuilder; - public SheetStyleBuildContext SheetStyleBuildContext { get; } = sheetStyleBuildContext; + public SheetStyleBuilderContext SheetStyleBuilderContext { get; } = sheetStyleBuilderContext; public void Dispose() { - SheetStyleBuildContext.Dispose(); + SheetStyleBuilderContext.Dispose(); Archive.Dispose(); _backingStream.Dispose(); } public async ValueTask DisposeAsync() { - await SheetStyleBuildContext.DisposeAsync().ConfigureAwait(false); + await SheetStyleBuilderContext.DisposeAsync().ConfigureAwait(false); #if NET10_0_OR_GREATER await Archive.DisposeAsync().ConfigureAwait(false); #else Archive.Dispose(); #endif -#if NET8_0_OR_GREATER await _backingStream.DisposeAsync().ConfigureAwait(false); -#else - _backingStream.Dispose(); -#endif } } } diff --git a/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.DefaultOpenXml.cs b/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.XmlGeneration.cs similarity index 91% rename from src/MiniExcel.OpenXml/Writer/OpenXmlWriter.DefaultOpenXml.cs rename to src/MiniExcel.OpenXml/Writer/OpenXmlWriter.XmlGeneration.cs index 6db4ac8b..6bd6091d 100644 --- a/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.DefaultOpenXml.cs +++ b/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.XmlGeneration.cs @@ -1,6 +1,3 @@ -using System.ComponentModel; -using MiniExcelLib.Core.Attributes; -using MiniExcelLib.OpenXml.Constants; using static MiniExcelLib.Core.Helpers.ImageHelper; namespace MiniExcelLib.OpenXml.Writer; @@ -188,7 +185,7 @@ private string GetPanes() if (type == typeof(TimeSpan)) return GetTimeSpanValue((TimeSpan)value, columnMapping); -#if NET8_0_OR_GREATER +#if NET if (type == typeof(DateOnly)) return GetDateTimeValue(((DateOnly)value).ToDateTime(default), columnMapping); @@ -216,23 +213,23 @@ private string GetPanes() var cellValue = GetNumericValue(value, type); if (columnMapping?.ExcelFormat is null) { - var dataType = ReferenceEquals(_configuration.Culture, CultureInfo.InvariantCulture) ? ExcelXml.NumericDataType : GetStringType(); + var dataType = ReferenceEquals(_configuration.Culture, CultureInfo.InvariantCulture) ? ExcelDataTypes.Numeric : GetStringType(); return (RegularCellStyleIndex, dataType, cellValue); } - return (columnMapping.ExcelFormatId.ToString(), ExcelXml.NumericDataType, cellValue); + return (columnMapping.ExcelFormatId.ToString(), ExcelDataTypes.Numeric, cellValue); } if (type == typeof(bool)) - return (RegularCellStyleIndex, ExcelXml.BooleanDataType, (bool)value ? "1" : "0"); + return (RegularCellStyleIndex, ExcelDataTypes.Boolean, (bool)value ? "1" : "0"); if (type == typeof(byte[]) && _configuration.EnableConvertByteArray) { if (!_configuration.EnableWriteFilePath) - return (FillCellStyleIndex, ExcelXml.CalculatedStringDataType, ""); + return (FillCellStyleIndex, ExcelDataTypes.CalculatedString, ""); var base64 = GetFileValue(rowIndex, cellIndex, value); - return (FillCellStyleIndex, ExcelXml.InlineStringDataType, base64); + return (FillCellStyleIndex, ExcelDataTypes.InlineString, base64); } return (RegularCellStyleIndex, GetStringType(), value.ToString()); @@ -240,11 +237,11 @@ private string GetPanes() string GetStringType() { if (columnMapping?.ExcelColumnType == ColumnType.Formula) - return ExcelXml.CalculatedStringDataType; + return ExcelDataTypes.CalculatedString; return _configuration.StringStorageMode == StringStorageMode.Shared - ? ExcelXml.SharedStringDataType - : ExcelXml.InlineStringDataType; + ? ExcelDataTypes.SharedString + : ExcelDataTypes.InlineString; } } @@ -332,14 +329,14 @@ private string GetFileValue(int rowIndex, int cellIndex, object value) if (!ReferenceEquals(_configuration.Culture, CultureInfo.InvariantCulture)) { cellValue = value.ToString(_configuration.Culture); - return (RegularCellStyleIndex, ExcelXml.CalculatedStringDataType, cellValue); + return (RegularCellStyleIndex, ExcelDataTypes.CalculatedString, cellValue); } var oaDate = CorrectDateTimeValue(value); cellValue = oaDate.ToString(CultureInfo.InvariantCulture); var format = columnMapping?.ExcelFormatId is { } fmt and not -1 ? fmt.ToString() : DateCellStyleIndex; - return (format, ExcelXml.NumericDataType, cellValue); + return (format, ExcelDataTypes.Numeric, cellValue); } private static double CorrectDateTimeValue(DateTime value) @@ -366,7 +363,7 @@ private static double CorrectDateTimeValue(DateTime value) var cellValue = value.TotalDays.ToString(CultureInfo.InvariantCulture); var format = columnMapping?.ExcelFormatId is { } fmt and not -1 ? fmt.ToString() : TimeCellStyleIndex; - return (format, ExcelXml.NumericDataType, cellValue); + return (format, ExcelDataTypes.Numeric, cellValue); } private static string GetDimensionRef(int maxRowIndex, int maxColumnIndex) @@ -383,7 +380,7 @@ private static string GetDimensionRef(int maxRowIndex, int maxColumnIndex) private string GetDrawingRelationshipXml(int sheetIndex) { var drawing = new StringBuilder(); - foreach (var image in _files.Where(w => w.IsImage && w.SheetId == sheetIndex + 1)) + foreach (var image in _files.Where(w => w.IsImage && w.SheetId == sheetIndex)) { drawing.AppendLine(ExcelXml.ImageRelationship(image)); } @@ -398,7 +395,7 @@ private string GetDrawingXml(int sheetIndex) for (int fileIndex = 0; fileIndex < _files.Count; fileIndex++) { var file = _files[fileIndex]; - if (file.IsImage && file.SheetId == sheetIndex + 1) + if (file.IsImage && file.SheetId == sheetIndex) { drawing.Append(ExcelXml.DrawingXml(file, fileIndex)); } diff --git a/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.cs b/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.cs index 0363b789..e59694df 100644 --- a/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.cs +++ b/src/MiniExcel.OpenXml/Writer/OpenXmlWriter.cs @@ -1,8 +1,4 @@ -using System.ComponentModel; -using System.Xml.Linq; -using MiniExcelLib.Core; using MiniExcelLib.Core.WriteAdapters; -using MiniExcelLib.OpenXml.Constants; using MiniExcelLib.OpenXml.Styles.Builder; namespace MiniExcelLib.OpenXml.Writer; @@ -22,8 +18,9 @@ internal partial class OpenXmlWriter : IMiniExcelWriter private readonly bool _printHeader; private readonly object? _value; - private int _currentSheetIndex = 0; - private SheetStyleBuildContext _sheetStyleBuildContext; + // the index is 1-based to match how the rels work in OpenXml and to make it more intuitive to reason about them + private int _currentSheetIndex; + private SheetStyleBuilderContext _sheetStyleBuilderContext; private OpenXmlWriter(Stream stream, ZipArchive archive, object? value, string sheetName, OpenXmlConfiguration configuration, bool printHeader) @@ -37,7 +34,7 @@ private OpenXmlWriter(Stream stream, ZipArchive archive, object? value, string s _printHeader = printHeader; _sheetName = sheetName; - _sheetStyleBuildContext = new SheetStyleBuildContext(_zipContentsMap, _archive, Utf8WithBom); + _sheetStyleBuilderContext = new SheetStyleBuilderContext(_zipContentsMap, _archive, Utf8WithBom); } [CreateSyncVersion] @@ -67,7 +64,7 @@ public async Task SaveAsAsync(IProgress? progress = null, Cancellati #endif await CreateZipEntryAsync(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels, cancellationToken).ConfigureAwait(false); - await using var sbc = _sheetStyleBuildContext.ConfigureAwait(false); + await using var sbc = _sheetStyleBuilderContext.ConfigureAwait(false); var styleBuilder = await GetSheetStyleBuilderAsync(cancellationToken).ConfigureAwait(false); var sheets = GetSheets(); @@ -105,7 +102,7 @@ public async Task InsertAsync(bool overwriteSheet = false, IProgress? #else using var disposableArchive = _archive; #endif - await using var sbc = _sheetStyleBuildContext.ConfigureAwait(false); + await using var sbc = _sheetStyleBuilderContext.ConfigureAwait(false); using var reader = await OpenXmlReader.CreateAsync(_stream, _configuration, cancellationToken: cancellationToken).ConfigureAwait(false); var rels = await reader.GetWorkbookRelsAsync(_archive.Entries, cancellationToken).ConfigureAwait(false) ?? []; @@ -158,11 +155,11 @@ public async Task InsertAsync(bool overwriteSheet = false, IProgress? sharedStringsEntry?.Delete(); await GenerateSharedStringsAsync(cancellationToken).ConfigureAwait(false); - _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(_currentSheetIndex - 1))?.Delete(); - await GenerateDrawingRelXmlAsync(_currentSheetIndex - 1, cancellationToken).ConfigureAwait(false); + _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(_currentSheetIndex))?.Delete(); + await GenerateDrawingRelXmlAsync(_currentSheetIndex, cancellationToken).ConfigureAwait(false); - _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(_currentSheetIndex - 1))?.Delete(); - await GenerateDrawingXmlAsync(_currentSheetIndex - 1, cancellationToken).ConfigureAwait(false); + _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(_currentSheetIndex))?.Delete(); + await GenerateDrawingXmlAsync(_currentSheetIndex, cancellationToken).ConfigureAwait(false); await GenerateWorkbookXmlAsync(true, cancellationToken).ConfigureAwait(false); await InsertContentTypesXmlAsync(cancellationToken).ConfigureAwait(false); @@ -175,12 +172,8 @@ private async Task CreateSheetXmlAsync(object? values, string sheetPath, IP var entry = _archive.CreateEntry(sheetPath, CompressionLevel.Fastest); var rowsWritten = 0; -#if NET8_0_OR_GREATER var zipStream = await entry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableZipStream = zipStream.ConfigureAwait(false); -#else - using var zipStream = entry.Open(); -#endif var writer = new MiniExcelStreamWriter(zipStream, Utf8WithBom, _configuration.BufferSize); await using var disposableWriter = writer.ConfigureAwait(false); @@ -253,7 +246,7 @@ private async Task WriteValuesAsync(MiniExcelStreamWriter writer, object va return 0; } - _sheetStyleBuildContext.UpdateFormatIds(mappings); + _sheetStyleBuilderContext.UpdateFormatIds(mappings); int maxRowIndex; var maxColumnIndex = mappings.Count(x => x is { ExcelIgnoreColumn: false }); @@ -433,7 +426,7 @@ private static async Task PrintHeaderAsync(MiniExcelStreamWriter writer, List GetSheetStyleBuilderAsync(CancellationTok { SheetStyleBuilderBase builder = _configuration.TableStyles switch { - TableStyles.None => new MinimalSheetStyleBuilder(_sheetStyleBuildContext), - TableStyles.Default => new DefaultSheetStyleBuilder(_sheetStyleBuildContext, _configuration.StyleOptions), + TableStyles.None => new MinimalSheetStyleBuilder(_sheetStyleBuilderContext), + TableStyles.Default => new DefaultSheetStyleBuilder(_sheetStyleBuilderContext, _configuration.StyleOptions), _ => throw new InvalidEnumArgumentException(nameof(_configuration.TableStyles), (int)_configuration.TableStyles, typeof(TableStyles)) }; var newInfos = builder.GetGeneratedElementInfos(); - await _sheetStyleBuildContext.CreateAsync(newInfos, cancellationToken).ConfigureAwait(false); + await _sheetStyleBuilderContext.CreateAsync(newInfos, cancellationToken).ConfigureAwait(false); return builder; } @@ -529,7 +522,7 @@ private async Task GetSheetStyleBuilderAsync(CancellationTok [CreateSyncVersion] private async Task GenerateDrawingRelXmlAsync(CancellationToken cancellationToken) { - for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) + for (int sheetIndex = 1; sheetIndex <= _sheets.Count; sheetIndex++) { cancellationToken.ThrowIfCancellationRequested(); await GenerateDrawingRelXmlAsync(sheetIndex, cancellationToken).ConfigureAwait(false); @@ -550,7 +543,7 @@ await CreateZipEntryAsync( [CreateSyncVersion] private async Task GenerateDrawingXmlAsync(CancellationToken cancellationToken) { - for (int sheetIndex = 0; sheetIndex < _sheets.Count; sheetIndex++) + for (int sheetIndex = 1; sheetIndex <= _sheets.Count; sheetIndex++) { cancellationToken.ThrowIfCancellationRequested(); await GenerateDrawingXmlAsync(sheetIndex, cancellationToken).ConfigureAwait(false); @@ -631,15 +624,10 @@ private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToke return; } -#if NET8_0_OR_GREATER var stream = await contentTypesZipEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableStream = stream.ConfigureAwait(false); - var doc = await XDocument.LoadAsync(stream, LoadOptions.None, cancellationToken).ConfigureAwait(false); -#else - using var stream = contentTypesZipEntry.Open(); - var doc = XDocument.Load(stream); -#endif + var doc = await XDocument.LoadAsync(stream, LoadOptions.None, cancellationToken).ConfigureAwait(false); var ns = doc.Root!.GetDefaultNamespace(); var typesElement = doc.Descendants(ns + "Types").Single(); @@ -662,12 +650,8 @@ private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToke } } - stream.Position = 0; -#if NET8_0_OR_GREATER + stream.Seek(0, SeekOrigin.Begin); await doc.SaveAsync(stream, SaveOptions.None, cancellationToken).ConfigureAwait(false); -#else - doc.Save(stream); -#endif } [CreateSyncVersion] @@ -677,12 +661,8 @@ private async Task CreateZipEntryAsync(string path, string? contentType, string var entry = _archive.CreateEntry(path, CompressionLevel.Fastest); -#if NET8_0_OR_GREATER var zipStream = await entry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableZipStream = zipStream.ConfigureAwait(false); -#else - using var zipStream = entry.Open(); -#endif var writer = new MiniExcelStreamWriter(zipStream, Utf8WithBom, _configuration.BufferSize); await using var disposableWriter = writer.ConfigureAwait(false); @@ -700,17 +680,18 @@ internal async Task AlterWorksheetAsync(string sheetName, string? newSheetName, if (newSheetName is null && newSheetIndex is null && newSheetState is null) return; - var oldWorkbookEntry = _archive.GetEntry("xl/workbook.xml")!; + var oldWorkbookEntry = _archive.GetEntry(ExcelFileNames.Workbook)!; try { var xmlDoc = await LoadWorkbook().ConfigureAwait(false); oldWorkbookEntry.Delete(); - var newWorkbookEntry = _archive.CreateEntry("xl/workbook.xml", CompressionLevel.Fastest); -#if NET8_0_OR_GREATER + var newWorkbookEntry = _archive.CreateEntry(ExcelFileNames.Workbook, CompressionLevel.Fastest); + var newZipStream = await newWorkbookEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var newDisposableZipStream = newZipStream.ConfigureAwait(false); +#if NET var writer = XmlWriter.Create(newZipStream, new XmlWriterSettings { #if !SYNC_ONLY @@ -720,7 +701,6 @@ internal async Task AlterWorksheetAsync(string sheetName, string? newSheetName, await using var disposableWriter = writer.ConfigureAwait(false); await xmlDoc.WriteToAsync(writer, CancellationToken.None).ConfigureAwait(false); #else - using var newZipStream = newWorkbookEntry.Open(); using var writer = XmlWriter.Create(newZipStream, new XmlWriterSettings { Async = false }); xmlDoc.WriteTo(writer); #endif @@ -737,14 +717,10 @@ internal async Task AlterWorksheetAsync(string sheetName, string? newSheetName, async Task LoadWorkbook() { -#if NET8_0_OR_GREATER var zipStream = await oldWorkbookEntry.OpenAsync(cancellationToken).ConfigureAwait(false); await using var disposableZipStream = zipStream.ConfigureAwait(false); + var workbookDoc = await XDocument.LoadAsync(zipStream, LoadOptions.None, cancellationToken).ConfigureAwait(false); -#else - using var zipStream = oldWorkbookEntry.Open(); - var workbookDoc = XDocument.Load(zipStream); -#endif var sheetsContainer = workbookDoc.Root?.Element((XNamespace)Schemas.SpreadsheetmlXmlMain + "sheets")!; var sheets = sheetsContainer.Elements().ToList(); diff --git a/tests/MiniExcel.Csv.Tests/AsyncIssueTests.cs b/tests/MiniExcel.Csv.Tests/AsyncIssueTests.cs index 5487c9e5..6ef7284a 100644 --- a/tests/MiniExcel.Csv.Tests/AsyncIssueTests.cs +++ b/tests/MiniExcel.Csv.Tests/AsyncIssueTests.cs @@ -5,8 +5,6 @@ public class AsyncIssueTests private readonly CsvExporter _csvExporter = MiniExcel.Exporters.GetCsvExporter(); private readonly CsvImporter _csvImporter = MiniExcel.Importers.GetCsvImporter(); - private readonly OpenXmlExporter _openXmlExporter = MiniExcel.Exporters.GetOpenXmlExporter(); - private readonly OpenXmlImporter _openXmlImporter = MiniExcel.Importers.GetOpenXmlImporter(); /// /// Csv SaveAs by datareader with encoding default show messy code #253 /// @@ -111,60 +109,36 @@ public enum WorkState [Fact] public async Task Issue89() { - { - const string text = - """ - State - OnDuty - Fired - Leave - """; - await using var stream = new MemoryStream(); - await using var writer = new StreamWriter(stream); - - await writer.WriteAsync(text); - await writer.FlushAsync(); - - stream.Position = 0; - var q = _csvImporter.QueryAsync(stream).ToBlockingEnumerable(); - var rows = q.ToList(); - - Assert.Equal(Issue89Dto.WorkState.OnDuty, rows[0].State); - Assert.Equal(Issue89Dto.WorkState.Fired, rows[1].State); - Assert.Equal(Issue89Dto.WorkState.Leave, rows[2].State); - - var outputPath = PathHelper.GetTempPath(); - var rowsWritten = await _openXmlExporter.ExportAsync(outputPath, rows); - Assert.Single(rowsWritten); - Assert.Equal(3, rowsWritten[0]); - - var q2 = _openXmlImporter.QueryAsync(outputPath).ToBlockingEnumerable(); - var rows2 = q2.ToList(); - Assert.Equal(Issue89Dto.WorkState.OnDuty, rows2[0].State); - Assert.Equal(Issue89Dto.WorkState.Fired, rows2[1].State); - Assert.Equal(Issue89Dto.WorkState.Leave, rows2[2].State); - } + const string text = + """ + State + OnDuty + Fired + Leave + """; - //xlsx - { - var path = PathHelper.GetFile("xlsx/TestIssue89.xlsx"); - var q = _openXmlImporter.QueryAsync(path).ToBlockingEnumerable(); - var rows = q.ToList(); - Assert.Equal(Issue89Dto.WorkState.OnDuty, rows[0].State); - Assert.Equal(Issue89Dto.WorkState.Fired, rows[1].State); - Assert.Equal(Issue89Dto.WorkState.Leave, rows[2].State); - - var outputPath = PathHelper.GetTempPath(); - var rowsWritten = await _openXmlExporter.ExportAsync(outputPath, rows); - Assert.Single(rowsWritten); - Assert.Equal(3, rowsWritten[0]); - - var q1 = _openXmlImporter.QueryAsync(outputPath).ToBlockingEnumerable(); - var rows2 = q1.ToList(); - Assert.Equal(Issue89Dto.WorkState.OnDuty, rows2[0].State); - Assert.Equal(Issue89Dto.WorkState.Fired, rows2[1].State); - Assert.Equal(Issue89Dto.WorkState.Leave, rows2[2].State); - } + await using var stream = new MemoryStream(); + await using var writer = new StreamWriter(stream); + + await writer.WriteAsync(text); + await writer.FlushAsync(); + + stream.Position = 0; + var rows1 = await _csvImporter.QueryAsync(stream).ToListAsync(); + + Assert.Equal(Issue89Dto.WorkState.OnDuty, rows1[0].State); + Assert.Equal(Issue89Dto.WorkState.Fired, rows1[1].State); + Assert.Equal(Issue89Dto.WorkState.Leave, rows1[2].State); + + var outputPath = PathHelper.GetTempPath(); + var rowsWritten = await MiniExcel.Exporters.GetOpenXmlExporter().ExportAsync(outputPath, rows1); + Assert.Single(rowsWritten); + Assert.Equal(3, rowsWritten[0]); + + var rows2 = await MiniExcel.Importers.GetOpenXmlImporter().QueryAsync(outputPath).ToListAsync(); + Assert.Equal(Issue89Dto.WorkState.OnDuty, rows2[0].State); + Assert.Equal(Issue89Dto.WorkState.Fired, rows2[1].State); + Assert.Equal(Issue89Dto.WorkState.Leave, rows2[2].State); } private class Issue142VoDuplicateColumnName @@ -184,76 +158,27 @@ private class Issue142VoDuplicateColumnName [Fact] public async Task Issue142() { - { - using var file = AutoDeletingPath.Create(); - var path = file.ToString(); - await _openXmlExporter.ExportAsync(path, new[] { new Issue142Dto { MyProperty1 = "MyProperty1", MyProperty2 = "MyProperty2", MyProperty3 = "MyProperty3", MyProperty4 = "MyProperty4", MyProperty5 = "MyProperty5", MyProperty6 = "MyProperty6", MyProperty7 = "MyProperty7" } }); - - { - var q = _openXmlImporter.QueryAsync(path).ToBlockingEnumerable(); - var rows = q.ToList(); - Assert.Equal("MyProperty4", rows[0].A); - Assert.Equal("CustomColumnName", rows[0].B); //note - Assert.Equal("MyProperty5", rows[0].C); - Assert.Equal("MyProperty2", rows[0].D); - Assert.Equal("MyProperty6", rows[0].E); - Assert.Null(rows[0].F); - Assert.Equal("MyProperty3", rows[0].G); - - Assert.Equal("MyProperty4", rows[0].A); - Assert.Equal("CustomColumnName", rows[0].B); //note - Assert.Equal("MyProperty5", rows[0].C); - Assert.Equal("MyProperty2", rows[0].D); - Assert.Equal("MyProperty6", rows[0].E); - Assert.Null(rows[0].F); - Assert.Equal("MyProperty3", rows[0].G); - } - - { - var q = _openXmlImporter.QueryAsync(path).ToBlockingEnumerable(); - var rows = q.ToList(); - - Assert.Equal("MyProperty4", rows[0].MyProperty4); - Assert.Equal("MyProperty1", rows[0].MyProperty1); //note - Assert.Equal("MyProperty5", rows[0].MyProperty5); - Assert.Equal("MyProperty2", rows[0].MyProperty2); - Assert.Equal("MyProperty6", rows[0].MyProperty6); - Assert.Null(rows[0].MyProperty7); - Assert.Equal("MyProperty3", rows[0].MyProperty3); - } - } - - { - using var file = AutoDeletingPath.Create(ExcelType.Csv); - var path = file.ToString(); - await _csvExporter.ExportAsync(path, new[] { new Issue142Dto { MyProperty1 = "MyProperty1", MyProperty2 = "MyProperty2", MyProperty3 = "MyProperty3", MyProperty4 = "MyProperty4", MyProperty5 = "MyProperty5", MyProperty6 = "MyProperty6", MyProperty7 = "MyProperty7" } }); - const string expected = - """ - MyProperty4,CustomColumnName,MyProperty5,MyProperty2,MyProperty6,,MyProperty3 - MyProperty4,MyProperty1,MyProperty5,MyProperty2,MyProperty6,,MyProperty3 - - """; - Assert.Equal(expected, await File.ReadAllTextAsync(path)); - - { - var q = _csvImporter.QueryAsync(path).ToBlockingEnumerable(); - var rows = q.ToList(); - - Assert.Equal("MyProperty4", rows[0].MyProperty4); - Assert.Equal("MyProperty1", rows[0].MyProperty1); - Assert.Equal("MyProperty5", rows[0].MyProperty5); - Assert.Equal("MyProperty2", rows[0].MyProperty2); - Assert.Equal("MyProperty6", rows[0].MyProperty6); - Assert.Null(rows[0].MyProperty7); - Assert.Equal("MyProperty3", rows[0].MyProperty3); - } - } + using var file = AutoDeletingPath.Create(ExcelType.Csv); + var path = file.ToString(); - { - using var path = AutoDeletingPath.Create(); - Issue142VoDuplicateColumnName[] input = [new() { MyProperty1 = 0, MyProperty2 = 0, MyProperty3 = 0, MyProperty4 = 0 }]; - Assert.Throws(() => _openXmlExporter.Export(path.ToString(), input)); - } + await _csvExporter.ExportAsync(path, new[] { new Issue142Dto { MyProperty1 = "MyProperty1", MyProperty2 = "MyProperty2", MyProperty3 = "MyProperty3", MyProperty4 = "MyProperty4", MyProperty5 = "MyProperty5", MyProperty6 = "MyProperty6", MyProperty7 = "MyProperty7" } }); + const string expected = + """ + MyProperty4,CustomColumnName,MyProperty5,MyProperty2,MyProperty6,,MyProperty3 + MyProperty4,MyProperty1,MyProperty5,MyProperty2,MyProperty6,,MyProperty3 + + """; + + Assert.Equal(expected, await File.ReadAllTextAsync(path)); + var rows = await _csvImporter.QueryAsync(path).ToListAsync(); + + Assert.Equal("MyProperty4", rows[0].MyProperty4); + Assert.Equal("MyProperty1", rows[0].MyProperty1); + Assert.Equal("MyProperty5", rows[0].MyProperty5); + Assert.Equal("MyProperty2", rows[0].MyProperty2); + Assert.Equal("MyProperty6", rows[0].MyProperty6); + Assert.Null(rows[0].MyProperty7); + Assert.Equal("MyProperty3", rows[0].MyProperty3); } /// @@ -273,8 +198,7 @@ public async Task Issue217() using var path = AutoDeletingPath.Create(ExcelType.Csv); await _csvExporter.ExportAsync(path.ToString(), table); - var q = _csvImporter.QueryAsync(path.ToString()).ToBlockingEnumerable(); - var rows = q.ToList(); + var rows = await _csvImporter.QueryAsync(path.ToString()).ToListAsync(); Assert.Equal("Name", rows[0].B); Assert.Equal("Limit", rows[0].C); } @@ -295,9 +219,7 @@ public async Task Issue237() }; await _csvExporter.ExportAsync(path.ToString(), value); - var q = _csvImporter.QueryAsync(path.ToString(), true).ToBlockingEnumerable(); - var rows = q.ToList(); - + var rows = await _csvImporter.QueryAsync(path.ToString(), true).ToListAsync(); Assert.Equal("\"\"1,2,3\"\"", rows[0].id); Assert.Equal("1,2,3", rows[1].id); } @@ -322,13 +244,11 @@ public async Task Issue241() Assert.Single(rowsWritten); Assert.Equal(2, rowsWritten[0]); - var q1 = _csvImporter.QueryAsync(path, true).ToBlockingEnumerable(); - var rows1 = q1.ToList(); + var rows1 = await _csvImporter.QueryAsync(path, true).ToListAsync(); Assert.Equal(rows1[0].InDate, "01 04, 2021"); Assert.Equal(rows1[1].InDate, "04 05, 2020"); - var q2 = _csvImporter.QueryAsync(path).ToBlockingEnumerable(); - var rows2 = q2.ToList(); + var rows2 = await _csvImporter.QueryAsync(path).ToListAsync(); Assert.Equal(rows2[0].InDate, new DateTime(2021, 01, 04)); Assert.Equal(rows2[1].InDate, new DateTime(2020, 04, 05)); } @@ -343,17 +263,16 @@ public async Task Issue243() using var path = AutoDeletingPath.Create(ExcelType.Csv); var value = new[] { - new { Name ="Jack",Age=25,InDate=new DateTime(2021,01,03)}, - new { Name ="Henry",Age=36,InDate=new DateTime(2020,05,03)}, + new { Name = "Jack", Age = 25, InDate = new DateTime(2021,01,03) }, + new { Name = "Henry", Age = 36, InDate = new DateTime(2020,05,03) } }; var rowsWritten = await _csvExporter.ExportAsync(path.ToString(), value); Assert.Single(rowsWritten); Assert.Equal(2, rowsWritten[0]); - var q = _csvImporter.QueryAsync(path.ToString()).ToBlockingEnumerable(); - var rows = q.ToList(); - + var rows = await _csvImporter.QueryAsync(path.ToString()).ToListAsync(); + Assert.Equal("Jack", rows[0].Name); Assert.Equal(25, rows[0].Age); Assert.Equal(new DateTime(2021, 01, 03), rows[0].InDate); diff --git a/tests/MiniExcel.Csv.Tests/IssueTests.cs b/tests/MiniExcel.Csv.Tests/IssueTests.cs index 47f8adcc..a8a8fe17 100644 --- a/tests/MiniExcel.Csv.Tests/IssueTests.cs +++ b/tests/MiniExcel.Csv.Tests/IssueTests.cs @@ -324,81 +324,6 @@ public void TestIssueI4Wda9() [Fact] public void TestIssue316() { - // XLSX - { - using var file = AutoDeletingPath.Create(); - var path = file.ToString(); - var value = new[] - { - new{ Amount=123_456.789M, CreateTime=DateTime.Parse("2018-01-31",CultureInfo.InvariantCulture)} - }; - var config = new OpenXmlConfiguration - { - Culture = new CultureInfo("fr-FR"), - }; - _openXmlExporter.Export(path, value, configuration: config); - - //Datetime error - Assert.Throws(() => - { - var conf = new OpenXmlConfiguration - { - Culture = new CultureInfo("en-US"), - }; - _ = _openXmlImporter.Query(path, configuration: conf).ToList(); - }); - - // dynamic - var rows = _openXmlImporter.Query(path, true).ToList(); - Assert.Equal("123456,789", rows[0].Amount); - Assert.Equal("31/01/2018 00:00:00", rows[0].CreateTime); - } - - // type - { - using var file = AutoDeletingPath.Create(); - var path = file.ToString(); - var value = new[] - { - new { Amount = 123_456.789M, CreateTime = new DateTime(2018, 5, 12) } - }; - { - var config = new OpenXmlConfiguration - { - Culture = new CultureInfo("fr-FR"), - }; - _openXmlExporter.Export(path, value, configuration: config); - } - - { - var rows = _openXmlImporter.Query(path, true).ToList(); - Assert.Equal("123456,789", rows[0].Amount); - Assert.Equal("12/05/2018 00:00:00", rows[0].CreateTime); - } - - { - var config = new OpenXmlConfiguration - { - Culture = new CultureInfo("en-US"), - }; - var rows = _openXmlImporter.Query(path, configuration: config).ToList(); - - Assert.Equal("2018-12-05 00:00:00", rows[0].CreateTime.ToString("yyyy-MM-dd HH:mm:ss")); - Assert.Equal(123456789m, rows[0].Amount); - } - - { - var config = new OpenXmlConfiguration - { - Culture = new CultureInfo("fr-FR"), - }; - var rows = _openXmlImporter.Query(path, configuration: config).ToList(); - - Assert.Equal("2018-05-12 00:00:00", rows[0].CreateTime.ToString("yyyy-MM-dd HH:mm:ss")); - Assert.Equal(123456.789m, rows[0].Amount); - } - } - // CSV { using var file = AutoDeletingPath.Create(ExcelType.Csv); @@ -677,53 +602,33 @@ public enum WorkState public void Issue89() { //csv - { - const string text = - """ - State - OnDuty - Fired - Leave - """; - - using var stream = new MemoryStream(); - using var writer = new StreamWriter(stream); - - writer.Write(text); - writer.Flush(); - stream.Position = 0; - var rows = _csvImporter.Query(stream, useHeaderRow: true).ToList(); - - Assert.Equal(nameof(Issue89Model.WorkState.OnDuty), rows[0].State); - Assert.Equal(nameof(Issue89Model.WorkState.Fired), rows[1].State); - Assert.Equal(nameof(Issue89Model.WorkState.Leave), rows[2].State); - - using var path = AutoDeletingPath.Create(ExcelType.Csv); - _csvExporter.Export(path.ToString(), rows); - var rows2 = _csvImporter.Query(path.ToString()).ToList(); + const string text = + """ + State + OnDuty + Fired + Leave + """; - Assert.Equal(Issue89Model.WorkState.OnDuty, rows2[0].State); - Assert.Equal(Issue89Model.WorkState.Fired, rows2[1].State); - Assert.Equal(Issue89Model.WorkState.Leave, rows2[2].State); - } + using var stream = new MemoryStream(); + using var writer = new StreamWriter(stream); - //xlsx - { - var path = PathHelper.GetFile("xlsx/TestIssue89.xlsx"); - var rows = _openXmlImporter.Query(path).ToList(); + writer.Write(text); + writer.Flush(); + stream.Position = 0; + var rows = _csvImporter.Query(stream, useHeaderRow: true).ToList(); - Assert.Equal(Issue89Model.WorkState.OnDuty, rows[0].State); - Assert.Equal(Issue89Model.WorkState.Fired, rows[1].State); - Assert.Equal(Issue89Model.WorkState.Leave, rows[2].State); + Assert.Equal(nameof(Issue89Model.WorkState.OnDuty), rows[0].State); + Assert.Equal(nameof(Issue89Model.WorkState.Fired), rows[1].State); + Assert.Equal(nameof(Issue89Model.WorkState.Leave), rows[2].State); - using var xlsxPath = AutoDeletingPath.Create(); - _openXmlExporter.Export(xlsxPath.ToString(), rows); - var rows2 = _openXmlImporter.Query(xlsxPath.ToString()).ToList(); + using var path = AutoDeletingPath.Create(ExcelType.Csv); + _csvExporter.Export(path.ToString(), rows); + var rows2 = _csvImporter.Query(path.ToString()).ToList(); - Assert.Equal(Issue89Model.WorkState.OnDuty, rows2[0].State); - Assert.Equal(Issue89Model.WorkState.Fired, rows2[1].State); - Assert.Equal(Issue89Model.WorkState.Leave, rows2[2].State); - } + Assert.Equal(Issue89Model.WorkState.OnDuty, rows2[0].State); + Assert.Equal(Issue89Model.WorkState.Fired, rows2[1].State); + Assert.Equal(Issue89Model.WorkState.Leave, rows2[2].State); } private class Issue142VoDuplicateColumnName diff --git a/tests/MiniExcel.OpenXml.Tests/MiniExcelOpenXmlAsyncTests.cs b/tests/MiniExcel.OpenXml.Tests/MiniExcelOpenXmlAsyncTests.cs index 31b58c15..de39a2a4 100644 --- a/tests/MiniExcel.OpenXml.Tests/MiniExcelOpenXmlAsyncTests.cs +++ b/tests/MiniExcel.OpenXml.Tests/MiniExcelOpenXmlAsyncTests.cs @@ -388,9 +388,7 @@ public async Task LargeFileQueryStrongTypeMapping_Test() [InlineData("../../../../data/xlsx/TestCenterEmptyRow/TestCenterEmptyRow.xlsx")] public async Task QueryExcelDataReaderCheckTest(string path) { -#if NETCOREAPP3_1_OR_GREATER Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); -#endif await using var fs = File.OpenRead(path); using var reader = ExcelReaderFactory.CreateReader(fs); diff --git a/tests/MiniExcel.OpenXml.Tests/MiniExcelOpenXmlTests.cs b/tests/MiniExcel.OpenXml.Tests/MiniExcelOpenXmlTests.cs index fedb55ef..14b663be 100644 --- a/tests/MiniExcel.OpenXml.Tests/MiniExcelOpenXmlTests.cs +++ b/tests/MiniExcel.OpenXml.Tests/MiniExcelOpenXmlTests.cs @@ -455,9 +455,8 @@ public void LargeFileQueryStrongTypeMapping_Test() [InlineData("../../../../data/xlsx/TestCenterEmptyRow/TestCenterEmptyRow.xlsx")] public void QueryDataReaderCheckTest(string path) { -#if NETCOREAPP3_1_OR_GREATER Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); -#endif + using var fs = File.OpenRead(path); using var reader = ExcelReaderFactory.CreateReader(fs); var exceldatareaderResult = reader.AsDataSet();