ClosedXML is a .NET library for reading, manipulating and writing Excel 2007+ (.xlsx, .xlsm) files. It aims to provide an intuitive and user-friendly interface to dealing with the underlying OpenXML API.
Add a warning about allowed ranges of DocumentFormat.OpenXML see issue #2220 and PR #2246.
Full Changelog: https://github.com/ClosedXML/ClosedXML/compare/0.102.1...0.102.2
Second test release for checking SourceLink support on nuget (first failed due to fody/PDB checksum) https://github.com/ClosedXML/ClosedXML/issues/2070
Test release for checking SourceLink support #2070
There won't be a non-beta release for 0.103. The production release will be 0.104, not 0.103. This milestone was about fixing technical debt, but ultimately it needs some more time to mature before it is sent to the users.
There are some nice performance updates, so in spirit of release early, release often, there will be a beta package on nuget.
Rich text is now immutable behind the scenes (and will likely be turned into immutable in the future). It should be transparent to the user, though IXLPhonetic
no longer has a setter for its IXLPhonetic.Text
, IXLPhonetic.Start
and IXLPhonetic.End
properties.
New calculation engine just works in a different way and will behave differently.
The XLParser has been replaced with ClosedParser. The key benefits are
There is also a visualizer to display AST in a browser at https://parser.closedxml.io
In previous version, formulas used to be calculated recursively. Each formula checked it's supporting cells for other formulas and if there were some, they were recursively evaluated. There was some logic to decrease number of evaluations. That works for a very simple cases, but isn't very good for various non-happy paths (i.e. cells weren't calculated when they should be).
This version has replaced it with a standard
For more info, see docs, the Microsoft has a page about principles Excel Recalculation and there is one with API at docs.closedxml.io.
Internal structure has been cleaned up and optimized.
The dirty tracking has been moved out of cells to formulas and thus memory taken up by a single cell value is now only 16 bytes instead of 24 (?) bytes in 0.102. Of course there are some other structures around that take up memory as well, but the single cell value is now 16 bytes (I hoped for 8, but not feasible with double
, DateTime
and TimeSpan
as possible cell values - all take up 8 bytes... not enough bits).
The same string in different instances is now not duplicated, but only one instance is used. As seen on following test, it can lead to significant decrease in memory consumption. 250k rows with 10 text rows (same string, different instance): 117 MiB om 0.103 vs 325 MiB in 0.102.1.
InsertData
performanceInsert 250k rows of 10 columns of text and 5 columns of numbers (gist).
Description | Rows | Columns | Time/Memory to insert data | Save workbook | Total time/memory |
---|---|---|---|---|---|
0.103.0-beta | 250 000 | 15 | 1.619 sec / 117 MiB | 6.343 sec | 477 MiB |
0.102.1 | 250 000 | 15 | 7.160 sec / 325 MiB | 6.676 sec | 692 MiB |
Basically workbooks with a large amount of cells should see ~15%-20% speedup (as long as there are mainly values, not styles or OLAP metadata....).
Reading the 250k from previous chapter:
Description | Rows | Columns | Time to load data | Used memory |
---|---|---|---|---|
0.103.0-beta | 250 000 | 15 | 15.648 sec | 236 MiB |
0.102.1 | 250 000 | 15 | 20.460 sec | 329 MiB |
Full Changelog: https://github.com/ClosedXML/ClosedXML/compare/0.102.0...0.103.0-beta
SixLabors.Fonts has released version 1.0.0 and some NET Framework projects suddently have errors due to NuGet behavior.
If a project is consuming ClosedXML through package.config
instead of PackageReference
style projects, the NuGet will resolve version 1.0.0 instead of declared beta19 dependency. SixLabors.Fonts has API changes and thus it will start to throw MissingMethodException
s.
The issue should only affect net framework projects, not dotnet core that use PackageReference
style by default.
Full Changelog: https://github.com/ClosedXML/ClosedXML/compare/0.102.0...0.102.1
Please read migration guide from 0.101 to 0.102. The key ones changes are:
IXLCell
is now a proxy to a sparse array and a new proxy is created each time it is requested by user code. Object.ReferenceEquals(ws.Cell("A1"), ws.Cell("A1"))
now evaluates to false
(used to be true
)IXLWorksheet AddWorksheet(DataTable dataTable)
and IXLWorksheet AddWorksheet(DataTable dataTable, string sheetName)
now use different name for the created table.The cells in a workbook used to be stored in a Dictionary<int, Dictionary<XLCell>>
. That has several significant drawbacks and the storage has been replaced with a sparse arrays of individual slices (basically a sparse array containing a specific part of a cell).
Key benefits (in long term):
Other than memory, it's a potential for the future. Replacing a storage engine is not simple and pretty much everything uses XLCell
adapter.
An example of different for 500k rows of value only cells (gist). About 200MB vs 900MB.
Default graphic engine of ClosedXML now contains an embedded font. That should be a quality of life improvement for users on Linux and other non-Windows environment who encountered
Unable to find font font name or fallback font fallback font name. Install missing fonts or specify a different fallback font through ‘LoadOptions.DefaultGraphicEngine = new DefaultGraphicEngine(“Fallback font name”)’..
The embedded font is an absolute bare bones Carlito font (though with a different name to avoid collision with the real one).
See doc for workflow of font selection: https://closedxml.readthedocs.io/en/latest/features/graphic-engine.html#fallback-and-embedded-font
A basic support for array formulas has been added. You can create array formula through IXLRangeBase
object.
csharp ws.Range("B2:D3").FormulaArrayA1 = "B1:D1*POWER(1+A2:A3, 2)";
For more info, see doc: https://closedxml.readthedocs.io/en/latest/features/formulas.html#array-formulas
The ancient PR from 2019 has been finally fixed and merged. It doesn't really add very useful features (multiple pivot tables don't have to have individual data store files in a xlsx file), but it is a big step to represent pivot cache data in a workbook. That is pretty much required to do anything useful with pivot tables.
The biggest visible improvement is that there is at least some very basic documentation about pivot tables https://closedxml.readthedocs.io/en/latest/features/pivot-tables.html
Some other OOXML producers (e.g. NPOI) don't add Normal style into a stylesheet and in 0.101 a feature had a missing null check leading to NullReferenceException
.
Not really something that is useful at this moment, but there has been significant work done on a replacement of a XLParser (https://github.com/ClosedXML/ClosedXML.Parser).
I hope to be done with the Phase 1 of my maintainership - architecture and dependencies. Most of the "OMG, this must be done before anything else" has been done. I hope to finish the rest (split writers of individual files from 5000+LOC file, use better parser and use calculation chain for formula evaluation) in the next one.
Full Changelog: https://github.com/ClosedXML/ClosedXML/compare/0.101.0...0.102.0
The cells in a workbook used to be stored in a Dictionary<int, Dictionary<XLCell>>
. That has several significant drawbacks and the storage has been replaced with a sparse arrays of individual slices (basically a sparse array containing a specific part of a cell).
Key benefits (in long term):
Other than memory, it's a potential for the future. Replacing a storage engine is not simple and pretty much everything uses XLCell
adapter.
An example of different for 500k rows of value only cells (gist). About 200MB vs 900MB.
Default graphic engine of ClosedXML now contains an embedded font. That should be a quality of life improvement for users on Linux and other non-Windows environment who encountered
Unable to find font font name or fallback font fallback font name. Install missing fonts or specify a different fallback font through ‘LoadOptions.DefaultGraphicEngine = new DefaultGraphicEngine(“Fallback font name”)’..
The embedded font is an absolute bare bones Carlito font (though with a different name to avoid collision with the real one).
See doc for workflow of font selection: https://closedxml.readthedocs.io/en/latest/features/graphic-engine.html#fallback-and-embedded-font
A basic support for array formulas has been added. You can create array formula through IXLRangeBase
object.
csharp ws.Range("B2:D3").FormulaArrayA1 = "B1:D1*POWER(1+A2:A3, 2)";
For more info, see doc: https://closedxml.readthedocs.io/en/latest/features/formulas.html#array-formulas
The ancient PR from 2019 has been finally fixed and merged. It doesn't really add very useful features (multiple pivot tables don't have to have individual data store files in a xlsx file), but it is a big step to represent pivot cache data in a workbook. That is pretty much required to do anything useful with pivot tables.
The biggest visible improvement is that there is at least some very basic documentation about pivot tables https://closedxml.readthedocs.io/en/latest/features/pivot-tables.html
Not really something that is useful at this moment, but there has been significant work done on a replacement of a XLParser (https://github.com/ClosedXML/ClosedXML.Parser).
I hope to be done with the Phase 1 of my maintainership - architecture and dependencies. Most of the "OMG, this must be done before anything else" has been done. I hope to finish the rest (split writers of individual files from 5000+LOC file, use better parser and use calculation chain for formula evaluation) in the next one.
Full Changelog: https://github.com/ClosedXML/ClosedXML/compare/0.101.0...0.102-rc
Mostly speed improvements, but some cool and nifty improvements, see changelog below.
Other than some enums being changed from int to byte, and a new method on IXLGraphicEngine
interface there should be no breaking changes in the release (see https://closedxml.readthedocs.io/en/latest/migrations/migrate-to-0.101.html).
Saving of cells in a worksheet has been significantly improved. As an example, a file of 100k rows and 44 columns (see gist) took 38 seconds to save in 0.100.3, but only 17 seconds in 0.101-rc .
Adjust to content has been refactored and it now calculates size of text by counting glyphs. Originally, we asked SixLabors.Fonts library to calculate it, but it is really slow (it has to deal with all possible typographic options, like having rtl and ltr text on same line).
It is faster to just use glyph size, plus I am pretty sure Excel also calculates width/height of a cell that way (likely legacy from earlier 90s version).
Time to run AdjustToContent
using a sample of 1000 rows.
Run# | 0.96.0 | 0.100.3 | 0.101-rc |
---|---|---|---|
1 | 168 ms | 1203 ms | 1674 ms |
2 | 4 ms | 568 ms | 31 ms |
3 | 4 ms | 551 ms | 25 ms |
4 | 4 ms | 540 ms | 26 ms |
5 | 3 ms | 544 ms | 25 ms |
6 | 3 ms | 550 ms | 26 ms |
7 | 4 ms | 556 ms | 46 ms |
8 | 3 ms | 556 ms | 28 ms |
9 | 4 ms | 541 ms | 23 ms |
10 | 3 ms | 535 ms | 23 ms |
Full Changelog: https://github.com/ClosedXML/ClosedXML/compare/0.100.3...0.101.0
Mostly speed improvements, but some cool and nifty improvements, see changelog below. Prod release will be 1 week after RC.
Other than some enums being changed from int to byte, and a new method on IXLGraphicEngine
interface there should be no breaking changes in the release (see https://closedxml.readthedocs.io/en/latest/migrations/migrate-to-0.101.html).
Saving of cells in a worksheet has been significantly improved. As an example, a file of 100k rows and 44 columns (see gist) took 38 seconds to save in 0.100.3, but only 17 seconds in 0.101-rc .
Adjust to content has been refactored and it now calculates size of text by counting glyphs. Originally, we asked SixLabors.Fonts library to calculate it, but it is really slow (it has to deal with all possible typographic options, like having rtl and ltr text on same line).
It is faster to just use glyph size, plus I am pretty sure Excel also calculates width/height of a cell that way (likely legacy from earlier 90s version).
Time to run AdjustToContent
using a sample of 1000 rows.
Run# | 0.96.0 | 0.100.3 | 0.101-rc |
---|---|---|---|
1 | 168 ms | 1203 ms | 1674 ms |
2 | 4 ms | 568 ms | 31 ms |
3 | 4 ms | 551 ms | 25 ms |
4 | 4 ms | 540 ms | 26 ms |
5 | 3 ms | 544 ms | 25 ms |
6 | 3 ms | 550 ms | 26 ms |
7 | 4 ms | 556 ms | 46 ms |
8 | 3 ms | 556 ms | 28 ms |
9 | 4 ms | 541 ms | 23 ms |
10 | 3 ms | 535 ms | 23 ms |
Full Changelog: https://github.com/ClosedXML/ClosedXML/compare/0.100.3...0.101.0
Fix a regression where some types of numbers were inserted as text by InsertData/InsertTable API.
// Only int and double were inserted as numbers, now all types are
cell.InsertData(new object[] { (sbyte)1, (byte)2, (short)3, (ushort)4, (uint)6, (long)7, (ulong)8, 15f, 17m });
Full Changelog: https://github.com/ClosedXML/ClosedXML/compare/0.100.2...0.100.3