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
5 changes: 5 additions & 0 deletions doc/版本日志.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# 版本功能更新记录

## v2.1.4
- ⚡️增加异步扩展方法`WriteExcelAsync`, 接收`IAsyncEnumerable<T>`的数据
- 🐞修复DateTime.ToOADate的显示问题
- 🛠代码重构

## v2.1.3

- 🐞读取行时,校验单元格的位置,确保索引正确
Expand Down
4 changes: 3 additions & 1 deletion src/LightExcel/ExcelConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
public class TransConfiguration
{
public bool SheetNumberFormat { get; set; }
internal ExcelConfiguration ExcelConfig { get; set; }
public Func<ExcelColumnInfo, bool> NumberFormatColumnFilter { get; set; }
public TransConfiguration()
public TransConfiguration(ExcelConfiguration configuration)
{
NumberFormatColumnFilter = col => SheetNumberFormat;
ExcelConfig = configuration;
}

}
Expand Down Expand Up @@ -76,7 +78,7 @@
}
else
{
return NeedToFormatNumberSheet.Contains(name) || NeedToFormatNumberSheet.Contains(sheetName);

Check warning on line 81 in src/LightExcel/ExcelConfiguration.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'item' in 'bool List<string>.Contains(string item)'.

Check warning on line 81 in src/LightExcel/ExcelConfiguration.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'item' in 'bool List<string>.Contains(string item)'.
}
}

Expand Down
21 changes: 9 additions & 12 deletions src/LightExcel/ExcelHelper.Stream.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using LightExcel.OpenXml;
using LightExcel.TypedDeserializer;
using LightExcel.Utils;
using System;
using System.Collections.Generic;
using System.IO;
Expand All @@ -9,29 +10,25 @@

namespace LightExcel
{
public partial class ExcelHelper
internal partial class ExcelHelper
{

public void WriteExcel(Stream stream, object data, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
public void WriteExcel(IDataRender render, Stream stream, object data, string sheetName = "Sheet1", ExcelConfiguration? config = null)
{
config?.Invoke(configuration);
using var trans = new TransExcelHelper(stream, configuration);
trans.WriteExcel(data, sheetName);
}
public void WriteExcelByTemplate(Stream stream, Stream templateStream, object data, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
{
config?.Invoke(configuration);
using var doc = ExcelDocument.CreateByTemplate(stream, templateStream, configuration);
HandleWriteTemplate(doc, data, sheetName);
config ??= new();
using var trans = new TransExcelHelper(stream, config);
trans.WriteExcel(render, data, sheetName);
}

public ITransactionExcelHelper BeginTransaction(Stream stream, Action<ExcelConfiguration>? config = null)
{
ExcelConfiguration configuration = new();
config?.Invoke(configuration);
return new TransExcelHelper(stream, configuration);
}

public IExcelDataReader ReadExcel(Stream stream, string? sheetName = null, Action<ExcelConfiguration>? config = null)
{
ExcelConfiguration configuration = new();
config?.Invoke(configuration);
var archive = ExcelDocument.Open(stream, configuration);
return new ExcelReader(archive, configuration, sheetName);
Expand Down
80 changes: 16 additions & 64 deletions src/LightExcel/ExcelHelper.Template.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,74 +9,26 @@

namespace LightExcel
{
public partial class ExcelHelper
internal partial class ExcelHelper
{
/// <summary>
/// 仅支持第一个sheet
/// </summary>
/// <param name="path"></param>
/// <param name="template"></param>
/// <param name="data"></param>
/// <param name="sheetName"></param>
/// <exception cref="Exception"></exception>
internal void HandleWriteTemplate(ExcelArchiveEntry doc, object data, string sheetName)
public void WriteExcelByTemplate(IDataRender render, ExcelArchiveEntry doc, object data, string sheetName = "Sheet1", ExcelConfiguration? config = null)
{
configuration.FillByTemplate = true;

// 获取sheet对象
var sheet = doc.WorkBook.WorkSheets.FirstOrDefault() ?? throw new Exception("read excel sheet failed");
// 获取最后一行当模板
var header = sheet.ToList();
var templateRow = header.Last();
// 获取共享字符串列表
var sst = doc.WorkBook.SharedStrings?.ToList();
var render = RenderProvider.GetDataRender(data.GetType(), configuration);
ExcelColumnInfo[]? columns = configuration.FillWithPlacholder ? [.. CollectExcelColumnInfos(templateRow, sst)] : [.. render.CollectExcelColumnInfo(data)];
sheet.Columns = columns;
if (configuration.FillWithPlacholder)
{
templateRow.IsTemplateRow = true;
configuration.StartRowIndex = templateRow.RowIndex - 1;
}
else
{
configuration.StartRowIndex = templateRow.RowIndex;
}
var newRows = render.RenderBody(data, sheet, columns, new TransConfiguration { SheetNumberFormat = configuration.AddSheetNumberFormat });
sheet.Replace(header.Concat(newRows));
doc.Save();
config ??= new ExcelConfiguration();
TransExcelHelper.WriteByTemplate(render, doc, data, sheetName, config);
}
#if NET8_0_OR_GREATER
[GeneratedRegex("{{(.+)}}")]
private static partial Regex ExtractColumn();
#else
static readonly Regex extract = new("{{(.+)}}");
private static Regex ExtractColumn() => extract;
#endif
private static IEnumerable<ExcelColumnInfo> CollectExcelColumnInfos(Row templateRow, List<SharedStringNode>? sst)
public void WriteExcelByTemplate(IDataRender render, string path, string template, object data, string sheetName = "Sheet1", ExcelConfiguration? config = null)
{
foreach (var cell in templateRow.Children)
{
string? name = cell.Value;
var (X, Y) = ReferenceHelper.ConvertCellReferenceToXY(cell.Reference);
if (cell.Type == "s")
{
if (int.TryParse(name, out var s) && sst!.Count > s)
{
name = sst[s].Content;
}
}
if (name != null)
{
var match = ExtractColumn().Match(name);
if (match.Success)
{
name = match.Groups[1].Value;
var col = new ExcelColumnInfo(name) { ColumnIndex = X ?? 0, StyleIndex = cell.StyleIndex };
yield return col;
}
}
}
config ??= new();
using var doc = ExcelDocument.CreateByTemplate(path, template, config);
TransExcelHelper.WriteByTemplate(render, doc, data, sheetName, config);
}

public void WriteExcelByTemplate(IDataRender render, Stream stream, Stream templateStream, object data, string sheetName = "Sheet1", ExcelConfiguration? config = null)
{
config ??= new();
using var doc = ExcelDocument.CreateByTemplate(stream, templateStream, config);
TransExcelHelper.WriteByTemplate(render, doc, data, sheetName, config);
}

}
}
33 changes: 15 additions & 18 deletions src/LightExcel/ExcelHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

namespace LightExcel
{
public partial class ExcelHelper : IExcelHelper
internal partial class ExcelHelper : IExcelHelper
{
private readonly ExcelConfiguration configuration = new ExcelConfiguration();

//public ExcelConfiguration configuration { get; set; } = new();
#region 读取
public IExcelDataReader ReadExcel(string path, string? sheetName = null, Action<ExcelConfiguration>? config = null)
{
ExcelConfiguration configuration = new ExcelConfiguration();
config?.Invoke(configuration);
var archive = ExcelDocument.Open(path, configuration);
return new ExcelReader(archive, configuration, sheetName);
Expand Down Expand Up @@ -49,29 +50,25 @@ public IEnumerable<dynamic> QueryExcel(string path, string? sheetName, Action<Ex
}
}
}
#endregion

public void WriteExcel(string path, object data, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
{
if (File.Exists(path)) File.Delete(path);
config?.Invoke(configuration);
using var trans = new TransExcelHelper(path, configuration);
trans.WriteExcel(data, sheetName);
}
public void WriteExcelByTemplate(string path, string template, object data, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
#region 写入

public void WriteExcel(IDataRender render, string path, object data, string sheetName = "Sheet1", ExcelConfiguration? config = null)
{
config ??= new();
if (File.Exists(path)) File.Delete(path);
config?.Invoke(configuration);
using var doc = ExcelDocument.CreateByTemplate(path, template, configuration);
HandleWriteTemplate(doc, data, sheetName);
using var trans = new TransExcelHelper(path, config);
trans.WriteExcel(render, data, sheetName);
}

public ITransactionExcelHelper BeginTransaction(string path, Action<ExcelConfiguration>? config = null)
public ITransactionExcelHelper BeginTransaction(ExcelArchiveEntry doc, ExcelConfiguration? config = null)
{
if (File.Exists(path)) File.Delete(path);
config?.Invoke(configuration);
return new TransExcelHelper(path, configuration);
config ??= new();
return new TransExcelHelper(doc, config);
}


#endregion
}
}
132 changes: 132 additions & 0 deletions src/LightExcel/Extensions/ExcelHeperExtensions.DIctionary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using LightExcel.OpenXml;
using LightExcel.Renders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightExcel;

public static partial class ExcelHeperExtensions
{
#region DictionaryRender - Dictionary<string, object>作为数据源

/// <summary>
/// <![CDATA[Dictionary<string, object>]]>数据源
/// </summary>
/// <param name="helper"></param>
/// <param name="path"></param>
/// <param name="datas"></param>
/// <param name="sheetName"></param>
/// <param name="config"></param>
public static void WriteExcel(this IExcelHelper helper, string path, IEnumerable<Dictionary<string, object>> datas, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
{
InternalWriteExcel<DictionaryRender>(helper, path, datas, sheetName, config);
}

/// <summary>
/// <![CDATA[Dictionary<string, object>]]>数据源
/// </summary>
/// <param name="helper"></param>
/// <param name="path"></param>
/// <param name="datas"></param>
/// <param name="sheetName"></param>
/// <param name="config"></param>
public static void WriteExcelByTemplate(this IExcelHelper helper, string path, string template, IEnumerable<Dictionary<string, object>> datas, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
{
InternalWriteExcelByTemplate<DictionaryRender>(helper, path, template, datas, sheetName, config);
}

/// <summary>
/// <![CDATA[Dictionary<string, object>]]>数据源
/// </summary>
/// <param name="helper"></param>
/// <param name="path"></param>
/// <param name="datas"></param>
/// <param name="sheetName"></param>
/// <param name="config"></param>
public static void WriteExcel(this IExcelHelper helper, Stream stream, IEnumerable<Dictionary<string, object>> datas, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
{
InternalWriteExcel<DictionaryRender>(helper, stream, datas, sheetName, config);
}

/// <summary>
/// <![CDATA[Dictionary<string, object>]]>数据源
/// </summary>
/// <param name="helper"></param>
/// <param name="path"></param>
/// <param name="datas"></param>
/// <param name="sheetName"></param>
/// <param name="config"></param>
public static void WriteExcelByTemplate(this IExcelHelper helper, Stream stream, Stream template, IEnumerable<Dictionary<string, object>> datas, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
{
InternalWriteExcelByTemplate<DictionaryRender>(helper, stream, template, datas, sheetName, config);
}

/// <summary>
/// <![CDATA[Dictionary<string, object>]]>数据源
/// </summary>
/// <param name="helper"></param>
/// <param name="path"></param>
/// <param name="datas"></param>
/// <param name="sheetName"></param>
/// <param name="config"></param>
public static void WriteExcelByTemplate(this IExcelHelper helper, string path, Stream templateStream, IEnumerable<Dictionary<string, object>> datas, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
{
InternalWriteExcelByTemplate<DictionaryRender>(helper, path, templateStream, datas, sheetName, config);
}

/// <summary>
/// <![CDATA[Dictionary<string, object>]]>数据源
/// </summary>
/// <param name="helper"></param>
/// <param name="path"></param>
/// <param name="datas"></param>
/// <param name="sheetName"></param>
/// <param name="config"></param>
public static void WriteExcelByTemplate(this IExcelHelper helper, Stream stream, string template, IEnumerable<Dictionary<string, object>> datas, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null)
{
InternalWriteExcelByTemplate<DictionaryRender>(helper, stream, template, datas, sheetName, config);
}

#endregion

#region 异步

#if NET6_0_OR_GREATER

public static async Task WriteExcelAsync(this IExcelHelper helper, string path, IAsyncEnumerable<Dictionary<string, object?>> data, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null, CancellationToken cancellationToken = default)
{
using var trans = helper.BeginTransaction(path, config);
//var render = new AsyncEnumerableEntityRender<T>(configuration);
await trans.WriteExcelAsync<AsyncDictionaryRender>(data, sheetName, cancellationToken: cancellationToken);
}

public static async Task WriteExcelAsync(this IExcelHelper helper, Stream stream, IAsyncEnumerable<Dictionary<string, object?>> data, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null, CancellationToken cancellationToken = default)
{
using var trans = helper.BeginTransaction(stream, config);
//var render = new AsyncEnumerableEntityRender<T>(configuration);
await trans.WriteExcelAsync<AsyncDictionaryRender>(data, sheetName, cancellationToken: cancellationToken);
}

/// <summary>
/// 实体数据-使用模板文件
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="helper"></param>
/// <param name="path"></param>
/// <param name="datas"></param>
/// <param name="sheetName"></param>
/// <param name="config"></param>
public static async Task WriteExcelByTemplateAsync(this IExcelHelper helper, string path, string template, IAsyncEnumerable<Dictionary<string, object?>> datas, string sheetName = "Sheet1", Action<ExcelConfiguration>? config = null, CancellationToken cancellationToken = default)
{
var configuration = new ExcelConfiguration();
config?.Invoke(configuration);
using var doc = ExcelDocument.CreateByTemplate(path, template, configuration);
await TransExcelHelper.WriteByTemplateAsync<AsyncDictionaryRender>(doc, datas, sheetName, configuration, cancellationToken);
}
#endif

#endregion
}
Loading
Loading