many debugs
All checks were successful
Publish NuGet packages / publish (push) Successful in 28s

This commit is contained in:
melekhin
2026-06-19 15:06:40 +07:00
parent 08b39b7bfe
commit e373d4108a
24 changed files with 1569 additions and 632 deletions

View File

@@ -8,9 +8,56 @@ namespace QWERTYkez.ExcelProcessor;
/// </summary>
internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
{
readonly Dictionary<CellStyle, int> _styleCache = [];
internal int GetOrCreateStyleId(CellStyle style)
{
lock (_syncLock)
{
if (_styleCache.TryGetValue(style, out int id))
return id;
// Создаём CellFormat через существующий метод GetOrCreateCellFormatId
int newId = GetOrCreateCellFormatId(
style.NumberFormat,
style.Font,
style.Fill,
style.Border,
style.Align
);
_styleCache[style] = newId;
return newId;
}
}
internal CellStyle? GetCellStyle(uint styleIndex)
{
if (styleIndex == 0) return null;
var align = GetCellAlign(styleIndex);
var font = GetCellFont(styleIndex);
var fill = GetCellFill(styleIndex);
var border = GetCellBorder(styleIndex);
var numberFormat = GetNumberFormat(styleIndex);
bool hasAny = !align.Equals(default) || !font.Equals(default) || !fill.Equals(default) ||
!border.Equals(default) || numberFormat != null;
if (!hasAny) return null;
return new CellStyle
{
Align = align.Equals(default) ? null : align,
Font = font.Equals(default) ? null : font,
Fill = fill.Equals(default) ? null : fill,
Border = border.Equals(default) ? null : border,
NumberFormat = numberFormat
};
}
// Работа с общей таблицей строк
private SharedStringTablePart? _sharedStringPart;
private SharedStringTable? _sharedStringTable;
SharedStringTablePart? _sharedStringPart;
SharedStringTable? _sharedStringTable;
internal static Dictionary<int, double>? _calibrationTable; // cw -> width_pts
@@ -62,7 +109,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
return true;
}
private Dictionary<int, double> CalibrateWidthCoeffUsingInterop()
Dictionary<int, double> CalibrateWidthCoeffUsingInterop()
{
object? excelApp = null;
object? workbooks = null;
@@ -133,7 +180,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
}
private void EnsureSharedStringTable()
void EnsureSharedStringTable()
{
if (_sharedStringPart != null) return;
_sharedStringPart = _doc.WorkbookPart?.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
@@ -193,17 +240,17 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
}
// Кэши числовых форматов
private readonly Dictionary<string, NumberFormatPattern> _numberFormatCache = [];
private readonly Dictionary<uint, NumberFormatPattern> _numberFormatIdToPattern = [];
readonly Dictionary<string, NumberFormatPattern> _numberFormatCache = [];
readonly Dictionary<uint, NumberFormatPattern> _numberFormatIdToPattern = [];
// Кэши для компонентов стилей (чтобы не создавать дубликаты)
private readonly Dictionary<CellFont, int> _fontCache = [];
private readonly Dictionary<CellFill, int> _fillCache = [];
private readonly Dictionary<CellBorder, int> _borderCache = [];
private readonly Dictionary<CellAlign, int> _alignmentCache = [];
readonly Dictionary<CellFont, int> _fontCache = [];
readonly Dictionary<CellFill, int> _fillCache = [];
readonly Dictionary<CellBorder, int> _borderCache = [];
readonly Dictionary<CellAlign, int> _alignmentCache = [];
// Кэш составных стилей (CellFormat)
private readonly Dictionary<(int fontId, int fillId, int borderId, int alignId, int numFmtId), int> _cellFormatCache = [];
readonly Dictionary<(int fontId, int fillId, int borderId, int alignId, int numFmtId), int> _cellFormatCache = [];
// Конструктор, фабричные методы без изменений (опущены)
@@ -294,10 +341,8 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
int numFmtId = -1;
if (numberFormat != null)
{
if (numberFormat.Id.HasValue && numberFormat.Id.Value < 164)
numFmtId = numberFormat.Id.Value;
else
numFmtId = (int)GetOrCreateNumberFormatId(numberFormat);
numFmtId = numberFormat.Id.HasValue && numberFormat.Id.Value < 164
? numberFormat.Id.Value : (int)GetOrCreateNumberFormatId(numberFormat);
}
// Получаем или создаём Font, Fill, Border, Alignment
@@ -352,7 +397,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
#region Вспомогательные методы для работы со стилями
private Stylesheet EnsureStylesheet()
Stylesheet EnsureStylesheet()
{
var workbookPart = _doc.WorkbookPart ?? throw new InvalidOperationException("No WorkbookPart");
var stylesPart = workbookPart.WorkbookStylesPart;
@@ -390,7 +435,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
return stylesheet;
}
private uint GetOrCreateNumberFormatId(NumberFormatPattern pattern)
uint GetOrCreateNumberFormatId(NumberFormatPattern pattern)
{
if (pattern.Id.HasValue)
return (uint)pattern.Id.Value;
@@ -400,7 +445,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
return (uint)created.Id!.Value;
}
private int GetOrCreateFontId(CellFont font)
int GetOrCreateFontId(CellFont font)
{
if (_fontCache.TryGetValue(font, out int id))
return id;
@@ -414,7 +459,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
return _fontCache[font] = (int)newId;
}
private int GetOrCreateFillId(CellFill fill)
int GetOrCreateFillId(CellFill fill)
{
if (_fillCache.TryGetValue(fill, out int id))
return id;
@@ -428,7 +473,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
return _fillCache[fill] = (int)newId;
}
private int GetOrCreateBorderId(CellBorder border)
int GetOrCreateBorderId(CellBorder border)
{
if (_borderCache.TryGetValue(border, out int id))
return id;
@@ -443,7 +488,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
return newId;
}
private int GetOrCreateAlignmentId(CellAlign align)
int GetOrCreateAlignmentId(CellAlign align)
{
if (_alignmentCache.TryGetValue(align, out int id))
return id;
@@ -456,7 +501,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
return id;
}
private Alignment GetAlignmentFromCache(int alignId)
Alignment GetAlignmentFromCache(int alignId)
{
foreach (var pair in _alignmentCache)
if (pair.Value == alignId)
@@ -464,7 +509,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
return new Alignment();
}
private CellFormat? GetCellFormatAt(uint index)
CellFormat? GetCellFormatAt(uint index)
{
var stylesheet = EnsureStylesheet();
if (stylesheet.CellFormats == null || index >= stylesheet.CellFormats.Count!.Value)
@@ -473,14 +518,14 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
}
// Вспомогательные создания коллекций
private static NumberingFormats CreateNumberingFormats(Stylesheet stylesheet)
static NumberingFormats CreateNumberingFormats(Stylesheet stylesheet)
{
var nfs = new NumberingFormats();
stylesheet.NumberingFormats = nfs;
return nfs;
}
private static CellFormats CreateCellFormats(Stylesheet stylesheet)
static CellFormats CreateCellFormats(Stylesheet stylesheet)
{
var cfs = new CellFormats();
stylesheet.CellFormats = cfs;
@@ -491,7 +536,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
private bool _isModified = false;
bool _isModified = false;
internal ExcelWriter() { }
@@ -1006,7 +1051,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
#endregion
private void EnsureFullCalculationOnLoad()
void EnsureFullCalculationOnLoad()
{
if (_doc?.WorkbookPart?.Workbook == null) return;
var workbook = _doc.WorkbookPart.Workbook;
@@ -1217,7 +1262,7 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
// Внутренний метод, предполагает, что _syncLock уже захвачен вызывающим
private NumberFormatPattern CreateNumberFormatInternal(string formatCode)
NumberFormatPattern CreateNumberFormatInternal(string formatCode)
{
// Проверяем кэш по коду
if (_numberFormatCache.TryGetValue(formatCode, out var existing))
@@ -1257,36 +1302,42 @@ internal sealed class ExcelWriter : ExcelReader, IExcelReader, IExcelWriter
// Вспомогательные методы для извлечения элементов из стилей (нужно закешировать или обращаться напрямую)
private Border? GetBorderById(uint borderId)
Border? GetBorderById(uint borderId)
{
if (_cachedBorders == null)
var borders = EnsureStylesheet().Borders;
if (borders == null) return null;
int index = 0;
foreach (var border in borders.Elements<Border>())
{
var borders = EnsureStylesheet().Borders;
_cachedBorders = borders?.Elements<Border>().ToList() ?? [];
if (index == borderId) return border;
index++;
}
return borderId < _cachedBorders.Count ? _cachedBorders[(int)borderId] : null;
return null;
}
private List<Border>? _cachedBorders;
private Fill? GetFillById(uint borderId)
Fill? GetFillById(uint fillId)
{
if (_cachedFills == null)
var fills = EnsureStylesheet().Fills;
if (fills == null) return null;
int index = 0;
foreach (var fill in fills.Elements<Fill>())
{
var fills = EnsureStylesheet().Fills;
_cachedFills = fills?.Elements<Fill>().ToList() ?? [];
if (index == fillId) return fill;
index++;
}
return borderId < _cachedFills.Count ? _cachedFills[(int)borderId] : null;
return null;
}
private List<Fill>? _cachedFills;
private Font? GetFontById(uint borderId)
Font? GetFontById(uint fontId)
{
if (_cachedFonts == null)
var fonts = EnsureStylesheet().Fonts;
if (fonts == null) return null;
int index = 0;
foreach (var font in fonts.Elements<Font>())
{
var borders = EnsureStylesheet().Borders;
_cachedFonts = borders?.Elements<Font>().ToList() ?? [];
if (index == fontId) return font;
index++;
}
return borderId < _cachedFonts.Count ? _cachedFonts[(int)borderId] : null;
return null;
}
private List<Font>? _cachedFonts;
}