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

## v2.1.3

- 🐞读取行时,校验单元格的位置,确保索引正确
- ⚡️优化读取时的内存占用

## v2.1.2

- ⚡️调整项目文件结构
- 🐞修复ExcelReader.CellAt方法的索引判断错误

2 changes: 1 addition & 1 deletion src/LightExcel/ExcelConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

internal ConcurrentDictionary<string, ExcelColumnInfo> DynamicColumns { get; set; } = new();

public ExcelColumnInfo? this[string name] => DynamicColumns.ContainsKey(name) ? DynamicColumns[name] : null;
public ExcelColumnInfo? this[string name] => DynamicColumns.TryGetValue(name, out ExcelColumnInfo? value) ? value : null;

public ExcelConfiguration AddDynamicColumnInfo(string name, Action<ExcelColumnInfo> info)
{
Expand Down Expand Up @@ -76,7 +76,7 @@
}
else
{
return NeedToFormatNumberSheet.Contains(name) || NeedToFormatNumberSheet.Contains(sheetName);

Check warning on line 79 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 79 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
24 changes: 15 additions & 9 deletions src/LightExcel/ExcelHelper.Template.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ public partial class ExcelHelper
internal void HandleWriteTemplate(ExcelArchiveEntry doc, object data, string sheetName)
{
configuration.FillByTemplate = true;

// 获取sheet对象
var sheet = doc.WorkBook.WorkSheets.FirstOrDefault() ?? throw new Exception("read excel sheet failed");
// 获取最后一行当模板
var templateRow = sheet.ToList().Last();
var header = sheet.ToList();
var templateRow = header.Last();
// 获取共享字符串列表
var sst = doc.WorkBook.SharedStrings?.ToList();
var render = RenderProvider.GetDataRender(data.GetType(), configuration);
var columns = configuration.FillWithPlacholder ? CollectExcelColumnInfos(templateRow, sst).ToArray() : render.CollectExcelColumnInfo(data).ToArray();
ExcelColumnInfo[]? columns = configuration.FillWithPlacholder ? [.. CollectExcelColumnInfos(templateRow, sst)] : [.. render.CollectExcelColumnInfo(data)];
sheet.Columns = columns;
if (configuration.FillWithPlacholder)
{
Expand All @@ -42,14 +43,19 @@ internal void HandleWriteTemplate(ExcelArchiveEntry doc, object data, string she
configuration.StartRowIndex = templateRow.RowIndex;
}
var newRows = render.RenderBody(data, sheet, columns, new TransConfiguration { SheetNumberFormat = configuration.AddSheetNumberFormat });
sheet.Replace(sheet.Concat(newRows));
sheet.Replace(header.Concat(newRows));
doc.Save();
}

static readonly Regex extract = new Regex("{{(.+)}}");
private IEnumerable<ExcelColumnInfo> CollectExcelColumnInfos(Row templateRow, List<SharedStringNode>? sst)
#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)
{
foreach (var cell in templateRow.RowDatas)
foreach (var cell in templateRow.Children)
{
string? name = cell.Value;
var (X, Y) = ReferenceHelper.ConvertCellReferenceToXY(cell.Reference);
Expand All @@ -62,7 +68,7 @@ private IEnumerable<ExcelColumnInfo> CollectExcelColumnInfos(Row templateRow, Li
}
if (name != null)
{
var match = extract.Match(name);
var match = ExtractColumn().Match(name);
if (match.Success)
{
name = match.Groups[1].Value;
Expand Down
27 changes: 16 additions & 11 deletions src/LightExcel/ExcelReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ internal class ExcelReader : IExcelDataReader

public string CurrentSheetName => sheetEnumerator.Current?.Name?.ToString() ?? "";

public int FieldCount => cells.Length;
public int FieldCount => cells.Count;
public int RowIndex => rowEnumerator?.Current.RowIndex ?? 0;
Cell[] cells = [];
List<Cell> cells = [];
string[] heads = [];

int startColumn = 1;
int startRow = 1;
int fixedColumn = 0;
public ExcelReader(ExcelArchiveEntry document, ExcelConfiguration configuration, string? targetSheet = null)
{
this.document = document;
Expand All @@ -42,12 +43,12 @@ public ExcelReader(ExcelArchiveEntry document, ExcelConfiguration configuration,

private Cell? CellAt(int i)
{
System.Diagnostics.Debug.WriteLine($"{RowIndex}: CellAt {i}, Enable {i < 0 || i >= cells.Length}");
if (i < 0 || i >= cells.Length)
//System.Diagnostics.Debug.WriteLine($"{RowIndex}: CellAt {i}, Enable {i + fixedColumn < 0 || i + fixedColumn >= cells.Count}");
if (i + fixedColumn < 0 || i + fixedColumn >= cells.Count)
return null;
return cells[i];
}

return cells[i + fixedColumn];
}

public bool GetBoolean(int i)
{
Expand Down Expand Up @@ -137,7 +138,7 @@ public bool NextResult()
rowEnumerator = sheetEnumerator.Current.GetEnumerator();
if (configuration.UseHeader && rowEnumerator.MoveNext())
{
heads = [.. rowEnumerator.Current.RowDatas.Select(c => c.GetCellValue(Sst) ?? "")];
heads = [.. rowEnumerator.Current.Children.Select(c => c.GetCellValue(Sst) ?? "")];
startRow += 1;
}
return true;
Expand Down Expand Up @@ -170,11 +171,15 @@ public bool Read()
{
if (HasRows)
{
//if (startColumn > 1)
// cells = rowEnumerator!.Current.RowDatas.Skip(startColumn - 1);
//else
if (startColumn > 1)
cells = [.. rowEnumerator!.Current.RowDatas.Skip(startColumn - 1)];
else
cells = [.. rowEnumerator!.Current.RowDatas];
System.Diagnostics.Debug.WriteLine($"{RowIndex}: Read, Cells {cells.Length}");
{
fixedColumn = startColumn - 1;
}
cells = rowEnumerator!.Current!.Children;
//System.Diagnostics.Debug.WriteLine($"{RowIndex}: Read, Cells {cells.Count}");
return true;
}
return false;
Expand Down
6 changes: 2 additions & 4 deletions src/LightExcel/LightExcel.csproj
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net45;net6.0;</TargetFrameworks>
<TargetFrameworks>net45;net6.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<Authors>MarvelTiter</Authors>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>MT.LightExcel</Title>
<Description>基于OpenXml的Excel读取与写入</Description>
<Version>2.1.2</Version>
<AssemblyVersion>2.1.2</AssemblyVersion>
<Version>2.1.3</Version>
<RepositoryUrl>https://github.com/MarvelTiter/LightExcel.git</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<FileVersion>2.1.2</FileVersion>
<PackageReadmeFile>Nuget.md</PackageReadmeFile>
</PropertyGroup>

Expand Down
50 changes: 26 additions & 24 deletions src/LightExcel/OpenXml/Basic/NodeCollectionXmlPart.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,38 @@
using System.IO.Compression;
using LightExcel.OpenXml.Interfaces;
using LightExcel.Utils;
using System.Collections;
namespace LightExcel.OpenXml.Basic;

namespace LightExcel.OpenXml
internal abstract class NodeCollectionXmlPart<T>(ZipArchive archive, string path) : XmlPart<T>(archive, path), INodeCollection<T> where T : INode
{
internal abstract class NodeCollectionXmlPart<T> : XmlPart<T>, INodeCollection<T> where T : INode
{

public NodeCollectionXmlPart(ZipArchive archive, string path) : base(archive, path)
{
public List<T> Children { get; } = new List<T>();

}
public int Count => Children.Count;

public int Count => cached?.Count ?? GetChildren().Count();
public void AppendChild(T child) => Children.Add(child);

public void AppendChild(T child)
{
cached ??= new List<T>();
cached.Add(child);
}
public override void Write()
public override void Write()
{
using var writer = archive!.GetWriter(Path);
WriteImpl(writer, Children);
}
protected virtual IEnumerable<T> GetChildren()
{
SetXmlReader();
if (reader == null) yield break;
foreach (var item in GetChildrenImpl())
{
using var writer = archive!.GetWriter(Path);
WriteImpl(writer, cached?.Cast<INode>() ?? Enumerable.Empty<INode>());
yield return item;
}
}

private IEnumerable<T> CollectSelfValues()
{
foreach (var item in this)
{
yield return item;
}
}
protected abstract IEnumerable<T> GetChildrenImpl();

public virtual IEnumerator<T> GetEnumerator() => GetChildren().GetEnumerator();

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
20 changes: 20 additions & 0 deletions src/LightExcel/OpenXml/Basic/SimpleNodeCollectionXmlPart.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections;
using LightExcel.OpenXml.Interfaces;

namespace LightExcel.OpenXml.Basic;

internal abstract class SimpleNodeCollectionXmlPart<T> : INodeCollection<T>, INode where T : INode
{
public IEnumerator<T> GetEnumerator() => Children.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public List<T> Children { get; } = [];
public void AppendChild(T child) => Children.Add(child);
public int Count => Children.Count;
public virtual void WriteToXml(LightExcelStreamWriter writer)
{

}
}
49 changes: 0 additions & 49 deletions src/LightExcel/OpenXml/Basic/XmlPart.Enumerator.cs

This file was deleted.

22 changes: 16 additions & 6 deletions src/LightExcel/OpenXml/Basic/XmlPart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,39 @@ internal abstract partial class XmlPart<T> : IXmlPart<T> where T : INode
{
private bool disposedValue;
protected ZipArchive? archive;
protected LightExcelXmlReader? reader = null;
internal virtual string Path { get; }
public XmlPart(ZipArchive archive, string path)
{
this.archive = archive;
Path = path;
}

protected IList<T>? cached;
protected virtual void SetXmlReader()
{
reader ??= archive!.GetXmlReader(Path);
}

public virtual void Write()
{

}

public void Write(IEnumerable<INode> children)
public void Write<TNode>(IEnumerable<TNode> children) where TNode : INode
{
using var writer = archive!.GetWriter(Path);
WriteImpl(writer, children);
}
public void Replace(IEnumerable<INode> children)
public void Replace<TNode>(IEnumerable<TNode> children) where TNode : INode
{
archive!.GetEntry(Path)?.Delete();
if (reader?.Path == Path)
{
reader?.Dispose();
reader = null;
archive!.GetEntry(Path)?.Delete();
}
Write(children);
}
protected abstract void WriteImpl(LightExcelStreamWriter writer, IEnumerable<INode> children);
protected abstract void WriteImpl<TNode>(LightExcelStreamWriter writer, IEnumerable<TNode> children) where TNode : INode;

protected virtual void Dispose(bool disposing)
{
Expand All @@ -45,6 +53,8 @@ protected virtual void Dispose(bool disposing)
{
archive?.Dispose();
archive = null;
reader?.Dispose();
reader = null;
}
disposedValue = true;
}
Expand Down
24 changes: 23 additions & 1 deletion src/LightExcel/OpenXml/Cell.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
using System.Text;
using LightExcel.OpenXml.Interfaces;
using LightExcel.Utils;

namespace LightExcel.OpenXml
{
internal class Cell : INode
internal struct Cell : INode
{
public Cell(){}
// public Cell(string? value, string? reference, string? type, string? style)
// {
// Value = value;
// Reference = reference;
// Type = type;
// StyleIndex = style;
// }
// public Cell(string? value, string? reference, string? type, string? style, int? index): this(value, reference, type, style)
// {
// ColumnIndex = index;
// }
public string? Reference { get; set; }
public string? Type { get; set; }
public string? StyleIndex { get; set; }
Expand All @@ -17,5 +30,14 @@ public void WriteToXml(LightExcelStreamWriter writer)
writer.Write($"<v>{Value}</v>");
writer.Write("</c>");
}

public static Cell EmptyCell(int x, int y)
{
var r = ReferenceHelper.ConvertXyToCellReference(x, y);
return new Cell
{
Reference = r
};
}
}
}
Loading
Loading