Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions src/MiniExcel.Core/Helpers/ExpandoHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,12 +21,7 @@ public static class ExpandoHelper
IDictionary<string, object?> 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;
Expand Down
9 changes: 4 additions & 5 deletions src/MiniExcel.Core/Helpers/MiniExcelStreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand All @@ -33,7 +32,7 @@ public async Task<long> WriteAndFlushAsync(string content, CancellationToken can
public async Task<long> FlushAndGetPositionAsync(CancellationToken cancellationToken = default)
{
await _streamWriter.FlushAsync(
#if NET8_0_OR_GREATER
#if NET
cancellationToken
#endif
Comment thread
michelebastione marked this conversation as resolved.
).ConfigureAwait(false);
Expand Down
81 changes: 78 additions & 3 deletions src/MiniExcel.Core/Helpers/Polyfills.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.ComponentModel;
using System.IO.Compression;
using System.Runtime.InteropServices;
using System.Xml.Linq;

namespace MiniExcelLib.Core.Helpers;

Expand All @@ -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<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue? defaultValue = default)
extension<TKey, TValue>(IDictionary<TKey, TValue> 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)]
Expand Down Expand Up @@ -45,6 +60,50 @@ public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSou
}
}
}

extension(Stream? stream)
{
[EditorBrowsable(EditorBrowsableState.Advanced)]
public ValueTask DisposeAsync()
{
if (stream is IAsyncDisposable asyncDisposable)
return asyncDisposable.DisposeAsync();

stream?.Dispose();
return default;
}

[EditorBrowsable(EditorBrowsableState.Advanced)]
public StreamConfiguredAsyncDisposable ConfigureAwait(bool continueOnCapturedContext)
=> new(stream, continueOnCapturedContext);
}

/// <summary>
/// This is a copy of the runtime's <see cref="ConfiguredAsyncDisposable" />, which we cannot instantiate directly for our needs
/// due to the constructor that initializes the object to eventually dispose being internal.
/// </summary>
[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
Expand All @@ -58,6 +117,22 @@ public ValueTask<Stream> OpenAsync(CancellationToken cancellationToken = default
}
}

extension(XDocument doc)
{
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static ValueTask<XDocument> LoadAsync(Stream stream, LoadOptions loadOptions, CancellationToken cancellationToken = default)
{
return new ValueTask<XDocument>(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)]
Expand Down
10 changes: 2 additions & 8 deletions src/MiniExcel.Core/MiniExcelDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions src/MiniExcel.Core/Reflection/MiniExcelMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
{
if (headersDic?.TryGetValue(alias, out var columnId) is true)
{
var columnName = keys[columnId];

Check warning on line 46 in src/MiniExcel.Core/Reflection/MiniExcelMapper.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.
item.TryGetValue(columnName, out var aliasItemValue);

if (aliasItemValue is not null)
Expand All @@ -62,7 +62,7 @@
}
else if (map.ExcelColumnName is not null && (headersDic?.TryGetValue(map.ExcelColumnName, out var columnId) is true))
{
var columnName = keys[columnId];

Check warning on line 65 in src/MiniExcel.Core/Reflection/MiniExcelMapper.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.
item.TryGetValue(columnName, out itemValue);
}

Expand Down Expand Up @@ -145,8 +145,8 @@
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)
Expand Down
10 changes: 6 additions & 4 deletions src/MiniExcel.Csv/Api/CsvExporter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using MiniExcelLib.Core;

// ReSharper disable once CheckNamespace
namespace MiniExcelLib.Csv;

Expand All @@ -20,7 +18,9 @@ public async Task<int> 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);
}

Expand All @@ -39,7 +39,9 @@ public async Task<int> AppendAsync(Stream stream, object value, CsvConfiguration
public async Task<int[]> ExportAsync(string path, object value, bool printHeader = true, bool overwriteFile = false,
CsvConfiguration? configuration = null, IProgress<int>? 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);
}

Expand Down
14 changes: 10 additions & 4 deletions src/MiniExcel.Csv/Api/CsvImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public async IAsyncEnumerable<T> QueryAsync<T>(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<T>(stream, treatHeaderAsData, configuration, cancellationToken);

Expand All @@ -38,7 +39,9 @@ public async IAsyncEnumerable<T> QueryAsync<T>(Stream stream, bool treatHeaderAs
public async IAsyncEnumerable<dynamic> 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;
}
Expand All @@ -64,7 +67,9 @@ public async IAsyncEnumerable<dynamic> QueryAsync(Stream stream, bool useHeaderR
public async Task<DataTable> 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);
}

Expand Down Expand Up @@ -127,7 +132,8 @@ public async Task<DataTable> QueryAsDataTableAsync(Stream stream, bool useHeader
public async Task<ICollection<string>> 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);
}

Expand Down
15 changes: 11 additions & 4 deletions src/MiniExcel.Csv/CsvReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
michelebastione marked this conversation as resolved.
).ConfigureAwait(false) is { } row)
Expand All @@ -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);
Expand Down Expand Up @@ -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
}
Loading
Loading