2021-03-26 13:46:08 +08:00
using System ;
2021-03-30 09:55:01 +08:00
using System.Collections.Generic ;
using System.ComponentModel ;
2021-03-26 13:46:08 +08:00
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
2021-06-21 04:58:06 +08:00
using System.Threading.Tasks ;
2021-03-30 09:55:01 +08:00
using BenchmarkDotNet.Attributes ;
using BenchmarkDotNet.Configs ;
using BenchmarkDotNet.Diagnosers ;
2021-03-30 21:36:27 +08:00
using BenchmarkDotNet.Order ;
2021-03-30 09:55:01 +08:00
using BenchmarkDotNet.Running ;
using ClosedXML.Excel ;
2021-03-30 21:36:27 +08:00
using DocumentFormat.OpenXml ;
2021-03-30 09:55:01 +08:00
using DocumentFormat.OpenXml.Packaging ;
using DocumentFormat.OpenXml.Spreadsheet ;
using ExcelDataReader ;
2021-03-26 13:46:08 +08:00
using MiniExcelLibs ;
2021-03-30 09:55:01 +08:00
using OfficeOpenXml ;
2021-03-26 13:46:08 +08:00
namespace MiniExcelLibs.Benchmarks
{
class Program
{
static void Main ( string [ ] args )
{
2021-03-30 09:55:01 +08:00
#if ! DEBUG
2021-05-05 11:36:19 +08:00
BenchmarkSwitcher . FromTypes ( new [ ] { typeof ( XlsxBenchmark ) } ) . Run ( args , new Config ( ) ) ;
2021-03-30 09:55:01 +08:00
#else
2021-05-05 11:36:19 +08:00
BenchmarkSwitcher . FromTypes ( new [ ] { typeof ( XlsxBenchmark ) } ) . Run ( args , new DebugInProcessConfig ( ) ) ;
//new TemplateXlsxBenchmark().MiniExcel_Template_Generate_Test();
2021-04-14 15:02:43 +08:00
//new XlsxBenchmark().MiniExcelCreateTest();
2021-03-30 09:55:01 +08:00
#endif
Console . Read ( ) ;
}
}
[BenchmarkCategory("Framework")]
[MemoryDiagnoser]
2021-03-30 21:36:27 +08:00
[SimpleJob(launchCount: 1, warmupCount: 1, targetCount: 1,invocationCount:1,baseline:false)]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
2021-03-30 09:55:01 +08:00
public abstract class BenchmarkBase
{
2021-03-30 21:36:27 +08:00
#if ! DEBUG
2021-05-05 11:36:19 +08:00
public const string filePath = @"Test10,000x10.xlsx" ;
public const int runCount = 1_000_000 ;
#else
public const string filePath = @"Test100x10.xlsx" ;
public const int runCount = 10 ;
#endif
//public const string filePath = @"Test10x10.xlsx";
//public const int runCount = 10;
public static IEnumerable < Demo > GetValues ( )
{
#if ! DEBUG
return Enumerable . Range ( 1 , runCount ) . Select ( s = > new Demo ( ) ) ;
2021-03-30 21:36:27 +08:00
#else
2021-05-05 11:36:19 +08:00
return Enumerable . Range ( 1 , runCount ) . Select ( s = > new Demo ( ) ) ;
2021-03-30 21:36:27 +08:00
#endif
2021-05-05 11:36:19 +08:00
}
2021-03-30 09:55:01 +08:00
}
2021-05-05 11:36:19 +08:00
public class XlsxBenchmark : BenchmarkBase
2021-04-14 15:02:43 +08:00
{
2021-05-05 11:36:19 +08:00
[GlobalSetup]
public void SetUp ( )
{
ExcelPackage . LicenseContext = OfficeOpenXml . LicenseContext . NonCommercial ;
System . Text . Encoding . RegisterProvider ( System . Text . CodePagesEncodingProvider . Instance ) ;
}
2021-04-14 15:02:43 +08:00
[Benchmark(Description = "MiniExcel Template Generate")]
public void MiniExcel_Template_Generate_Test ( )
{
{
var path = Path . Combine ( Path . GetTempPath ( ) , $"{Guid.NewGuid().ToString()}.xlsx" ) ;
2021-05-05 11:36:19 +08:00
const string templatePath = @"TestTemplateBasicIEmumerableFill.xlsx" ;
2021-04-14 15:02:43 +08:00
var value = new
{
2021-05-05 11:36:19 +08:00
employees = Enumerable . Range ( 1 , runCount ) . Select ( s = > new { name = "Jack" , department = "HR" } )
2021-04-14 15:02:43 +08:00
} ;
MiniExcel . SaveAsByTemplate ( path , templatePath , value ) ;
}
}
2021-06-21 04:58:06 +08:00
[Benchmark(Description = "MiniExcel Async Template Generate")]
public async Task MiniExcel_Template_Generate_Async_Test ( )
{
{
var path = Path . Combine ( Path . GetTempPath ( ) , $"{Guid.NewGuid().ToString()}.xlsx" ) ;
const string templatePath = @"TestTemplateBasicIEmumerableFill.xlsx" ;
var value = new
{
employees = Enumerable . Range ( 1 , runCount ) . Select ( s = > new { name = "Jack" , department = "HR" } )
} ;
await MiniExcel . SaveAsByTemplateAsync ( path , templatePath , value ) ;
}
}
2021-04-14 15:02:43 +08:00
[Benchmark(Description = "ClosedXml.Report Template Generate")]
public void ClosedXml_Report_Template_Generate_Test ( )
{
{
var path = Path . Combine ( Path . GetTempPath ( ) , $"{Guid.NewGuid().ToString()}.xlsx" ) ;
2021-05-05 11:36:19 +08:00
var templatePath = @"TestTemplateBasicIEmumerableFill_ClosedXML_Report.xlsx" ;
2021-04-14 15:02:43 +08:00
var template = new ClosedXML . Report . XLTemplate ( templatePath ) ;
var value = new
{
2021-05-05 11:36:19 +08:00
employees = Enumerable . Range ( 1 , runCount ) . Select ( s = > new { name = "Jack" , department = "HR" } )
2021-04-14 15:02:43 +08:00
} ;
template . AddVariable ( value ) ;
template . Generate ( ) ;
template . SaveAs ( path ) ;
}
}
2021-03-30 09:55:01 +08:00
[Benchmark(Description = "MiniExcel QueryFirst")]
public void MiniExcel_QueryFirst_Test ( )
{
MiniExcel . Query ( filePath ) . First ( ) ;
}
2021-03-30 21:36:27 +08:00
[Benchmark(Description = "MiniExcel Query")]
public void MiniExcel_Query ( )
{
foreach ( var item in MiniExcel . Query ( filePath ) )
{
}
}
2021-03-30 09:55:01 +08:00
[Benchmark(Description = "ExcelDataReader QueryFirst")]
public void ExcelDataReader_QueryFirst_Test ( )
{
2021-03-30 21:36:27 +08:00
#if DEBUG
System . Text . Encoding . RegisterProvider ( System . Text . CodePagesEncodingProvider . Instance ) ;
#endif
2021-03-30 09:55:01 +08:00
using ( var stream = File . Open ( filePath , FileMode . Open , FileAccess . Read ) )
using ( var reader = ExcelReaderFactory . CreateReader ( stream ) )
{
var d = new List < object > ( ) ;
reader . Read ( ) ;
for ( int i = 0 ; i < reader . FieldCount ; i + + )
d . Add ( reader . GetValue ( i ) ) ;
}
}
2021-03-30 21:36:27 +08:00
[Benchmark(Description = "ExcelDataReader Query")]
public void ExcelDataReader_Query_Test ( )
{
#if DEBUG
System . Text . Encoding . RegisterProvider ( System . Text . CodePagesEncodingProvider . Instance ) ;
#endif
using ( var stream = File . Open ( filePath , FileMode . Open , FileAccess . Read ) )
using ( var reader = ExcelReaderFactory . CreateReader ( stream ) )
{
while ( reader . Read ( ) )
{
var d = new List < object > ( ) ;
for ( int i = 0 ; i < reader . FieldCount ; i + + )
d . Add ( reader . GetValue ( i ) ) ;
}
}
}
2021-03-30 09:55:01 +08:00
[Benchmark(Description = "Epplus QueryFirst")]
public void Epplus_QueryFirst_Test ( )
{
2021-03-30 21:36:27 +08:00
#if DEBUG
ExcelPackage . LicenseContext = OfficeOpenXml . LicenseContext . NonCommercial ;
#endif
2021-03-30 09:55:01 +08:00
using ( var p = new ExcelPackage ( new FileInfo ( filePath ) ) )
{
p . Workbook . Worksheets [ 0 ] . Row ( 1 ) ;
}
}
2021-03-30 21:36:27 +08:00
[Benchmark(Description = "Epplus Query")]
public void Epplus_Query_Test ( )
{
#if DEBUG
ExcelPackage . LicenseContext = OfficeOpenXml . LicenseContext . NonCommercial ;
#endif
// [c# - How do I iterate through rows in an excel table using epplus? - Stack Overflow](https://stackoverflow.com/questions/21742038/how-do-i-iterate-through-rows-in-an-excel-table-using-epplus)
using ( var p = new ExcelPackage ( new FileInfo ( filePath ) ) )
{
var workSheet = p . Workbook . Worksheets [ 0 ] ;
var start = workSheet . Dimension . Start ;
var end = workSheet . Dimension . End ;
for ( int row = start . Row ; row < = end . Row ; row + + )
{ // Row by row...
for ( int col = start . Column ; col < = end . Column ; col + + )
{ // ... Cell by cell...
object cellValue = workSheet . Cells [ row , col ] . Text ; // This got me the actual value I needed.
}
}
}
}
2021-03-30 09:55:01 +08:00
[Benchmark(Description = "ClosedXml QueryFirst")]
public void ClosedXml_QueryFirst_Test ( )
{
using ( var workbook = new XLWorkbook ( filePath ) )
{
workbook . Worksheet ( 1 ) . Row ( 1 ) ;
}
}
2021-03-30 21:36:27 +08:00
[Benchmark(Description = "ClosedXml Query")]
public void ClosedXml_Query_Test ( )
{
using ( var workbook = new XLWorkbook ( filePath ) )
{
workbook . Worksheet ( 1 ) . Rows ( ) ;
}
}
2021-03-30 09:55:01 +08:00
[Benchmark(Description = "OpenXmlSDK QueryFirst")]
public void OpenXmlSDK_QueryFirst_Test ( )
{
using ( SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument . Open ( filePath , false ) )
{
WorkbookPart workbookPart = spreadsheetDocument . WorkbookPart ;
WorksheetPart worksheetPart = workbookPart . WorksheetParts . First ( ) ;
SheetData sheetData = worksheetPart . Worksheet . Elements < SheetData > ( ) . First ( ) ;
var firstRow = sheetData . Elements < Row > ( ) . First ( ) ;
}
}
2021-03-30 21:36:27 +08:00
[Benchmark(Description = "OpenXmlSDK Query")]
public void OpenXmlSDK_Query_Test ( )
{
using ( SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument . Open ( filePath , false ) )
{
WorkbookPart workbookPart = spreadsheetDocument . WorkbookPart ;
WorksheetPart worksheetPart = workbookPart . WorksheetParts . First ( ) ;
SheetData sheetData = worksheetPart . Worksheet . Elements < SheetData > ( ) . First ( ) ;
var firstRow = sheetData . Elements < Row > ( ) . ToList ( ) ;
}
}
[Benchmark(Description = "MiniExcel Create Xlsx")]
2021-03-30 09:55:01 +08:00
public void MiniExcelCreateTest ( )
{
2021-03-30 21:36:27 +08:00
var values = GetValues ( ) ;
2021-03-30 09:55:01 +08:00
var path = Path . Combine ( Path . GetTempPath ( ) , $"{Guid.NewGuid().ToString()}.xlsx" ) ;
using ( var stream = File . Create ( path ) )
stream . SaveAs ( values ) ;
2021-03-30 21:36:27 +08:00
File . Delete ( path ) ;
}
2021-06-21 04:58:06 +08:00
[Benchmark(Description = "MiniExcel Async Create Xlsx")]
public async Task MiniExcelCreateAsyncTest ( )
{
var values = GetValues ( ) ;
var path = Path . Combine ( Path . GetTempPath ( ) , $"{Guid.NewGuid().ToString()}.xlsx" ) ;
using ( var stream = File . Create ( path ) )
await stream . SaveAsAsync ( values ) ;
File . Delete ( path ) ;
}
2021-03-30 21:36:27 +08:00
[Benchmark(Description = "ClosedXml Create Xlsx")]
public void ClosedXmlCreateTest ( )
{
var values = GetValues ( ) ;
var path = Path . Combine ( Path . GetTempPath ( ) , $"{Guid.NewGuid().ToString()}.xlsx" ) ;
using ( var wb = new XLWorkbook ( ) )
{
var ws = wb . Worksheets . Add ( "Inserting Data" ) ;
ws . Cell ( 1 , 1 ) . InsertData ( values ) ;
wb . SaveAs ( path ) ;
}
File . Delete ( path ) ;
}
[Benchmark(Description = "Epplus Create Xlsx")]
public void EpplusCreateTest ( )
{
#if DEBUG
ExcelPackage . LicenseContext = OfficeOpenXml . LicenseContext . NonCommercial ;
#endif
var values = GetValues ( ) ;
var path = Path . Combine ( Path . GetTempPath ( ) , $"{Guid.NewGuid().ToString()}.xlsx" ) ;
using ( var excelFile = new ExcelPackage ( new FileInfo ( path ) ) )
{
var worksheet = excelFile . Workbook . Worksheets . Add ( "Sheet1" ) ;
worksheet . Cells [ "A1" ] . LoadFromCollection ( Collection : values , PrintHeaders : true ) ;
excelFile . Save ( ) ;
}
File . Delete ( path ) ;
}
[Benchmark(Description = "OpenXmlSdk Create Xlsx")]
public void OpenXmlSdkCreateTest ( )
{
var path = Path . Combine ( Path . GetTempPath ( ) , $"{Guid.NewGuid().ToString()}.xlsx" ) ;
// Create a spreadsheet document by supplying the filepath.
// By default, AutoSave = true, Editable = true, and Type = xlsx.
2021-06-21 04:58:06 +08:00
2021-03-30 21:36:27 +08:00
using ( SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument . Create ( path , SpreadsheetDocumentType . Workbook ) )
{
// Add a WorkbookPart to the document.
WorkbookPart workbookpart = spreadsheetDocument . AddWorkbookPart ( ) ;
workbookpart . Workbook = new Workbook ( ) ;
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = workbookpart . AddNewPart < WorksheetPart > ( ) ;
worksheetPart . Worksheet = new Worksheet ( new SheetData ( ) ) ;
// Add Sheets to the Workbook.
Sheets sheets = spreadsheetDocument . WorkbookPart . Workbook .
AppendChild < Sheets > ( new Sheets ( ) ) ;
// Append a new worksheet and associate it with the workbook.
Sheet sheet = new Sheet ( )
{
Id = spreadsheetDocument . WorkbookPart .
GetIdOfPart ( worksheetPart ) ,
SheetId = 1 ,
Name = "Sheet1"
} ;
sheets . Append ( sheet ) ;
var sheetData = worksheetPart . Worksheet . GetFirstChild < SheetData > ( ) ;
foreach ( var item in GetValues ( ) )
{
var row = new Row ( ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text1 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text2 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text3 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text4 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text5 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text6 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text7 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text8 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text9 ) , DataType = CellValues . String } ) ;
row . Append ( new Cell ( ) { CellValue = new CellValue ( item . Text10 ) , DataType = CellValues . String } ) ;
sheetData . AppendChild ( row ) ;
}
workbookpart . Workbook . Save ( ) ;
}
File . Delete ( path ) ;
}
2021-05-05 11:36:19 +08:00
}
2021-03-30 21:36:27 +08:00
2021-05-05 11:36:19 +08:00
public class Demo
{
public string Text1 { get ; set ; } = "Hello World" ;
public string Text2 { get ; set ; } = "Hello World" ;
public string Text3 { get ; set ; } = "Hello World" ;
public string Text4 { get ; set ; } = "Hello World" ;
public string Text5 { get ; set ; } = "Hello World" ;
public string Text6 { get ; set ; } = "Hello World" ;
public string Text7 { get ; set ; } = "Hello World" ;
public string Text8 { get ; set ; } = "Hello World" ;
public string Text9 { get ; set ; } = "Hello World" ;
public string Text10 { get ; set ; } = "Hello World" ;
2021-03-26 13:46:08 +08:00
}
}