diff --git a/README.md b/README.md index cf8ac4c..04b868d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ --- -[English](README.md) / [繁體中文](README.zh-tw.md) +[English](README.md) / [繁體中文](README.zh-tw.md) / [简体中文](README.zh-Hans.md) --- diff --git a/README.zh-Hans.md b/README.zh-Hans.md new file mode 100644 index 0000000..a9fcfeb --- /dev/null +++ b/README.zh-Hans.md @@ -0,0 +1,312 @@ +[![NuGet](https://img.shields.io/nuget/v/MiniExcel.svg)](https://www.nuget.org/packages/MiniExcel) [![](https://img.shields.io/nuget/dt/MiniExcel.svg)](https://www.nuget.org/packages/MiniExcel) [![Build status](https://ci.appveyor.com/api/projects/status/b2vustrwsuqx45f4/branch/master?svg=true)](https://ci.appveyor.com/project/shps951023/miniexcel/branch/master) [![.NET Framework](https://img.shields.io/badge/.NET%20Framework-%3E%3D%204.6.1-red.svg)](#) [![.NET Standard](https://img.shields.io/badge/.NET%20Standard-%3E%3D%202.0-red.svg)](#) [![.NET](https://img.shields.io/badge/.NET%20-%3E%3D%205.0-red.svg)](#) + +--- + +[English](README.md) / [繁體中文](README.zh-tw.md) / [简体中文](README.zh-Hans.md) + +--- + +### 简介 + +MiniExcel 简单、高效避免OOM的.NET处理Excel工具。 + + +目前主流框架大多需要将资料全载入到内存方便操作,但这会导致内存消耗问题,MiniExcel 尝试以 Stream 角度写底层算法逻辑,能让原本1000多MB占用降低到几MB,避免内存不够情况。 + +![image](https://user-images.githubusercontent.com/12729184/113120478-33d59980-9244-11eb-8675-a49651c8af67.png) + +### 特点 + +- 低内存耗用,避免OOM(out of memoery)、频繁 Full GC 情况 +- 支持`即时`操作每行数据 + ![miniexcel_lazy_load](https://user-images.githubusercontent.com/12729184/111034290-e5588a80-844f-11eb-8c84-6fdb6fb8f403.gif) +- 兼具搭配 LINQ 延迟查询特性,能办到低消耗、快速分页等复杂查询 + 图片:与主流框架对比的消耗、效率差 + ![queryfirst](https://user-images.githubusercontent.com/12729184/111072392-6037a900-8515-11eb-9693-5ce2dad1e460.gif) +- 轻量,不依赖任何套件,DLL小于100KB +- 简便操作的 Dapper API 风格 + +### 安装 + +请查看 [from NuGet](https://www.nuget.org/packages/MiniExcel) + +### 更新日志 + +请查看 [Release Notes](https://github.com/shps951023/MiniExcel/tree/master/docs) + +### TODO + +请查看 [Project · todo](https://github.com/shps951023/MiniExcel/projects/1?fullscreen=true) + +### 性能测试 + +以 [**Test1,000,000x10.xlsx**](https://github.com/shps951023/MiniExcel/blob/master/samples/xlsx/Test1%2C000%2C000x10/Test1%2C000%2C000x10.xlsx) 做基准与主流框架做性能测试,总共 1千万笔 "HelloWorld",文件大小 23 MB + +Benchmarks 逻辑可以在 [MiniExcel.Benchmarks](https://github.com/shps951023/MiniExcel/tree/master/benchmarks/MiniExcel.Benchmarks) 查看或是提交 PR,运行指令 + +``` +dotnet run -p .\benchmarks\MiniExcel.Benchmarks\ -c Release -f netcoreapp3.1 -- -f * --join +``` + +最后一次运行结果 : + +``` +BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042 +Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + [Host] : .NET Framework 4.8 (4.8.4341.0), X64 RyuJIT + Job-ZYYABG : .NET Framework 4.8 (4.8.4341.0), X64 RyuJIT +IterationCount=3 LaunchCount=3 WarmupCount=3 +``` + +| Method | 最大内存耗用 | 平均时间 | Gen 0 | Gen 1 | Gen 2 | +| ---------------------------- | -----------: | ---------------: | -----------: | ----------: | ---------: | +| 'MiniExcel QueryFirst' | 0.109 MB | 726.4 us | - | - | - | +| 'ExcelDataReader QueryFirst' | 15.24 MB | 10,664,238.2 us | 566000.0000 | 1000.0000 | - | +| 'MiniExcel Query' | 17.3 MB | 14,179,334.8 us | 367000.0000 | 96000.0000 | 7000.0000 | +| 'Epplus QueryFirst' | 1,452 MB | 18,198,015.4 us | 535000.0000 | 132000.0000 | 9000.0000 | +| 'ExcelDataReader Query' | 17.3 MB | 22,565,088.7 us | 1210000.0000 | 2000.0000 | - | +| 'Epplus Query' | 1,451 MB | 23,647,471.1 us | 1451000.0000 | 133000.0000 | 9000.0000 | +| 'OpenXmlSDK Query' | 1,412 MB | 52,003,270.1 us | 978000.0000 | 353000.0000 | 11000.0000 | +| 'OpenXmlSDK QueryFirst' | 1,413 MB | 52,348,659.1 us | 978000.0000 | 353000.0000 | 11000.0000 | +| 'ClosedXml QueryFirst' | 2,158 MB | 66,188,979.6 us | 2156000.0000 | 575000.0000 | 9000.0000 | +| 'ClosedXml Query' | 2,184 MB | 191,434,126.6 us | 2165000.0000 | 577000.0000 | 10000.0000 | + + +| Method | 最大内存耗用 | 平均时间 | Gen 0 | Gen 1 | Gen 2 | +| ------------------------ | -----------: | ---------------: | -----------: | -----------: | ---------: | +| 'MiniExcel Create Xlsx' | 15 MB | 11,531,819.8 us | 1020000.0000 | - | - | +| 'Epplus Create Xlsx' | 1,204 MB | 22,509,717.7 us | 1370000.0000 | 60000.0000 | 30000.0000 | +| 'OpenXmlSdk Create Xlsx' | 2,621 MB | 42,473,998.9 us | 1370000.0000 | 460000.0000 | 50000.0000 | +| 'ClosedXml Create Xlsx' | 7,141 MB | 140,939,928.6 us | 5520000.0000 | 1500000.0000 | 80000.0000 | + +### Query 查询 Excel 返回`强型别` IEnumerable 数据 [[Try it]](https://dotnetfiddle.net/w5WD1J) + +推荐使用 Stream.Query 效率会相对较好。 + +```C# +public class UserAccount +{ + public Guid ID { get; set; } + public string Name { get; set; } + public DateTime BoD { get; set; } + public int Age { get; set; } + public bool VIP { get; set; } + public decimal Points { get; set; } +} + +var rows = MiniExcel.Query(path); + +// or + +using (var stream = File.OpenRead(path)) + var rows = stream.Query(); +``` + +![image](https://user-images.githubusercontent.com/12729184/111107423-c8c46b80-8591-11eb-982f-c97a2dafb379.png) + + +### Query 查询 Excel 返回`Dynamic` IEnumerable 数据 [[Try it]](https://dotnetfiddle.net/w5WD1J) + +* Key 系统预设为 `A,B,C,D...Z` + +| MiniExcel | 1 | +| --------- | ---- | +| Github | 2 | + +```C# +var rows = MiniExcel.Query(path).ToList(); + +// or +using (var stream = File.OpenRead(path)) +{ + var rows = stream.Query().ToList(); + + Assert.Equal("MiniExcel", rows[0].A); + Assert.Equal(1, rows[0].B); + Assert.Equal("Github", rows[1].A); + Assert.Equal(2, rows[1].B); +} +``` + +### 查询数据以第一行数据当Key [[Try it]](https://dotnetfiddle.net/w5WD1J) + +note : 同名以右边数据为准 + +Input Excel : + +| Column1 | Column2 | +| --------- | ------- | +| MiniExcel | 1 | +| Github | 2 | + + +```C# +var rows = MiniExcel.Query(useHeaderRow:true).ToList(); + +// or + +using (var stream = File.OpenRead(path)) +{ + var rows = stream.Query(useHeaderRow:true).ToList(); + + Assert.Equal("MiniExcel", rows[0].Column1); + Assert.Equal(1, rows[0].Column2); + Assert.Equal("Github", rows[1].Column1); + Assert.Equal(2, rows[1].Column2); +} +``` + +### Query 查询支援延迟加载(Deferred Execution),能配合LINQ First/Take/Skip办到低消耗、高效率复杂查询 + +Query First + +```C# +var row = MiniExcel.Query(path).First(); +Assert.Equal("HelloWorld", row.A); + +// or + +using (var stream = File.OpenRead(path)) +{ + var row = stream.Query().First(); + Assert.Equal("HelloWorld", row.A); +} +``` + +### 建立 Excel 文件 [[Try it]](https://dotnetfiddle.net/w5WD1J) + +1. 必须是 non-abstract 类别有 public parameterless constructor +2. MiniExcel SaveAs 支援 `IEnumerable参数``延迟查询`,除非必要请不要使用 ToList 等方法读取全部数据到内存 + +图片 : 是否呼叫 ToList 的内存差别 +![image](https://user-images.githubusercontent.com/12729184/112587389-752b0b00-8e38-11eb-8a52-cfb76c57e5eb.png) + +Anonymous or strongly type: + +```C# +var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx"); +MiniExcel.SaveAs(path, new[] { + new { Column1 = "MiniExcel", Column2 = 1 }, + new { Column1 = "Github", Column2 = 2} +}); +``` + +Datatable: + +```C# +var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx"); +var table = new DataTable(); +{ + table.Columns.Add("Column1", typeof(string)); + table.Columns.Add("Column2", typeof(decimal)); + table.Rows.Add("MiniExcel", 1); + table.Rows.Add("Github", 2); +} + +MiniExcel.SaveAs(path, table); +``` + +Dapper: + +```C# +using (var connection = GetConnection(connectionString)) +{ + var rows = connection.Query(@"select 'MiniExcel' as Column1,1 as Column2 union all select 'Github',2"); + MiniExcel.SaveAs(path, rows); +} +``` + +`IEnumerable>` + +```C# +var values = new List>() +{ + new Dictionary{{ "Column1", "MiniExcel" }, { "Column2", 1 } }, + new Dictionary{{ "Column1", "Github" }, { "Column2", 2 } } +}; +MiniExcel.SaveAs(path, values); +``` + +output : + +| Column1 | Column2 | +| --------- | ------- | +| MiniExcel | 1 | +| Github | 2 | + +### SaveAs 支援 Stream [[Try it]](https://dotnetfiddle.net/JOen0e) + +```C# +using (var stream = File.Create(path)) +{ + stream.SaveAs(values); +} +``` + + +### 例子 : SQLite & Dapper 读取大数据新增到数据库 + +note : 请不要呼叫 call ToList/ToArray 等方法,这会将所有数据读到内存内 + +```C# +using (var connection = new SQLiteConnection(connectionString)) +{ + connection.Open(); + using (var transaction = connection.BeginTransaction()) + using (var stream = File.OpenRead(path)) + { + var rows = stream.Query(); + foreach (var row in rows) + connection.Execute("insert into T (A,B) values (@A,@B)", new { row.A, row.B }, transaction: transaction); + transaction.Commit(); + } +} +``` + +效能: +![image](https://user-images.githubusercontent.com/12729184/111072579-2dda7b80-8516-11eb-9843-c01a1edc88ec.png) + + +### 例子 : ASP.NET Core 3.1 or MVC 5 下载 Excel Xlsx API Demo + +```C# +public class ExcelController : Controller +{ + public IActionResult Download() + { + var values = new[] { + new { Column1 = "MiniExcel", Column2 = 1 }, + new { Column1 = "Github", Column2 = 2} + }; + var stream = new MemoryStream(); + stream.SaveAs(values); + return File(stream, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "demo.xlsx"); + } +} +``` + +### Excel 类别自动判断 + +MiniExcel 预设会根据扩展名或是 Stream 类别判断是 xlsx 还是 csv,但会有失准时候,请自行指定。 + +```C# +stream.SaveAs(excelType:ExcelType.CSV); +//or +stream.SaveAs(excelType:ExcelType.XLSX); +//or +stream.Query(excelType:ExcelType.CSV); +//or +stream.Query(excelType:ExcelType.XLSX); +``` + +### 局限与警告 + +- 目前不支援 xls (97-2003) 或是加密文件。 +- 不支援样式、字体、宽度等`修改`,因为 MiniExcel 概念是只专注于值数据,借此降低内存消耗跟提升效率。 + +### 参考 + +- 读取逻辑 : [ExcelDataReader](https://github.com/ExcelDataReader/ExcelDataReader) +- API 设计方式 : [StackExchange/Dapper](https://github.com/StackExchange/Dapper) \ No newline at end of file diff --git a/README.zh-tw.md b/README.zh-tw.md index a0e1519..b2f982a 100644 --- a/README.zh-tw.md +++ b/README.zh-tw.md @@ -2,7 +2,7 @@ --- -[English](README.md) / [繁體中文](README.zh-tw.md) +[English](README.md) / [繁體中文](README.zh-tw.md) / [简体中文](README.zh-Hans.md) --- @@ -175,8 +175,8 @@ using (var stream = File.OpenRead(path)) ### 建立 Excel 檔案 [[Try it]](https://dotnetfiddle.net/w5WD1J) -1. 必須是 non-abstract 類別有公開建構式 -2. MiniExcel SaveAs 支援 `IEnumerable參數``延遲查詢`,除非必要請不要使用 ToList 等方法讀取全部資料到記憶體,請看圖片了解差異 +1. 必須是 non-abstract 類別有 public parameterless constructor +2. MiniExcel SaveAs 支援 `IEnumerable參數``延遲查詢`,除非必要請不要使用 ToList 等方法讀取全部資料到記憶體 圖片 : 是否呼叫 ToList 的記憶體差別 ![image](https://user-images.githubusercontent.com/12729184/112587389-752b0b00-8e38-11eb-8a52-cfb76c57e5eb.png) @@ -298,6 +298,7 @@ stream.Query(excelType:ExcelType.XLSX); ### 侷限與警告 - 目前不支援 xls (97-2003) 或是加密檔案。 +- 不支援樣式、字體、寬度等`修改`,因為 MiniExcel 概念是只專注於值資料,藉此降低記憶體消耗跟提升效率。 ### 參考 - 讀取邏輯 : [ExcelDataReader](https://github.com/ExcelDataReader/ExcelDataReader) diff --git a/docs/core logic 1.drawio b/docs/core logic 1.drawio index bde660a..6b22970 100644 --- a/docs/core logic 1.drawio +++ b/docs/core logic 1.drawio @@ -1 +1 @@ -7Ztdj6I6GIB/TS9PwrflUhw8m+yYmcSLMzl3FaqSAUoKrrq//rSlKLZM4mbjlmHOjZaXIvI+fT+rwF0Up78pqvYrkuIcOFZ6Au4TcBzbsRz2xiXnVjKzglawo1kqJ10F6+wnlkJLSg9ZiuubiQ0heZNVt8KElCVOmhsZopQcb6dtSX571wrtsCZYJyjXpf9kabNvpdC3rvJvONvtuzvbljxToG6yFNR7lJJjT+TGwF1QQpp2VJwWOOfK6/TSXrf84Ozli1FcNvdcsEqfi3f072EVnI7l7q2p5/j7X177KT9QfpAP/Pa8fgNxAMIAwBmIPRBFIGLMgpzdJdpQNtrxEYghmM/A3AWxz19DNpiBiAlj+bzNuVMie/SKD+sGV+zSCtOswA2mUvR6PY6O+6zB6wolfP6RrSkm2zdFzo5sNtxmJ9ytkvY4zxckJ1TcyE0RhtuEyeuGknfcOxMkEG+2/Hu3D4xpg08fatK+8GELGxP25eiZTZEXXBanXNO2K4+P1xVid9j3vdUBpQzJRbm7fPSVGxtIdL+A0dcwxqdEWGIPE2Mag9Dig8gH0Oa85hDASONFyaFMMb+hdQ8SAwg8hYB3J4HgUQQCjcCA5jUjeqlw+bZ6nrrBuHBsBgMHcHnce0FhMZChW3BucxvAQAKMAo3Tr5nGFiY4GVT2Bvqebz3ENBw3NGwanbdUbQOCEHLVMgUz1cYhmEcg9MzZwp/BowYPx7mTz8Nswbb/5/OxrxoBH0fjs8rKTEb43/JIqY9h6g2pFDobNwge4pFc48HadjWNrhuKUXHNjcxF5D+CRPVCrvGIbOulCK8sIktkqlCUGE/CC9k8GLNTPEj7U3dHvhrOzbsjvdgQmRLkZBgWBgeK6jB6AjAUAWQJQr3ImFiOq4Iyn+PawzVJtORRnIOKhCHNuMdry0JepSymDioIRwdq9tXDkZp0jSAc6RXi68viZagPFvBIFDJjs9JziYosGZg0cX6q8xsBv3A4nYhkLcNsKhJxK1zyLIInGCy1cIb49voCvB2wGJJobnXiwFUnah54dzMFOPR5ZsKBu2LAQLmisS063GE49fxRBWU+f3QG2g3S6tLsR2d2YhvCsZjOcHeW3a03YeCaQ/kzqz6aPe2kRq3nPGjcHvWuRbcngUqUn+us5k9ISYLrWsPz6XYgvPBOhT+sqeHoTY0BG3lFtM7K3d02ddmh+IpWpaalI7AqvUvSWdWSogIfCX3XqHyCXQofmt6lcPS2xgoXRH7yhDMENXT4M+MZgt64+BooVH8zAhR6a+JT7z0E5sO03liQzZ6Jl4yqnwnMB1O9R8Dj54YQFkP5rzVQwRXZvuqdAT633mPcTN0tqd0d826p6zb03ZL86aHOKSEle/w6I6VBEzOyB2E+X3X1Yp8cmupg0GbM7DKMAIVekH+NwKNmVeYDj6uX6sObC0wdvV2FaWNSndcIMOnF9hPeYkpxOhho4hNOmkMjAo16jpIju2bDn1cMp81S9X4jYKmX90hcJf4iMPEETsXxyASOHV7/0yDO9f4Z4sb/AQ== \ No newline at end of file +7Vzdj6o4FP9r+rgJ35ZHUdxNdszcZB52sm8IVckANQWvzv3rty1FscW9zG68ZWBetByKyPn1fPcA7EV+/p1Eh/0aJygDlpGcgb0ElmVahkW/GOW9pswMrybsSJqISVfCS/oDCaIhqMc0QeXNxArjrEoPt8QYFwWKqxtaRAg+3U7b4uz2rodohxTCSxxlKvWvNKn2NRW6xpX+B0p3++bOpiHO5FEzWRDKfZTgU4tkh8BeEIyrepSfFyhjzGv4Ul+3unP28scIKqo+F6yTp/wt+vu49s6nYvdalXP0529O/Svfo+woHvj16eUVhB7wPQBnIHRAEICAYuZl9C7BhtDRjo1ACMF8BuY2CF326dPBDASUGIrnrd4bJtJHP7BhWaEDvfSASJqjChFB+nY9Dk77tEIvhyhm8090TVHavsozemTS4TY9o2aV1MdZtsAZJvxGdhIhuI0pvawIfkOtM14M0WbL/nf9wIhU6HyXk+YFH7qwEaZ/jrzTKeKCy+IUa9q0xfHpukLMBvZ9a3VAQYvEotxdfvqKGx0I6D4Ao6vAGJ5jLoktmCimIfANNghcAE2G1xwCGCh4EXwsEsRuaPSBRAMEjoSA0xMB71EIeAoCHZxXhOj5gIrX9dPYBcaGQxMY2AGXw7QX5BIDKXQLhtvcBNATAAaegtPHRGMLYxR3MnsDXcc1HiIalu1rFo1GW8qyAYEPGWspgylrQx/MA+A7+mTh18AjGw/L6onPw2TBNL/wua+rBoCPpeCzTotUWPj/pZESF8HE6WIptDa25z1EI9najbVpKxx9qQiK8qtvpM8i/xJIZC1ka7fIphqKsMgiMLinCnmIseRayGTGmJ5iRtoduzpyZXOuXx2pwQb3lCBDhsJCwYE8OgyWAPrcgKyArwYZI/NxZaD0+7hmd0wSrJgVZ0AFXJBmTOPVYSGLUhZjB8rzBwfUbOrmSHa6BmCO1Ajx2/PiuSsP5jFL5FNhM5L3IsrTuGPSyPGTld8A8PO73YlAxDJUpgJut/wV8yKYg0FdC6sL31ZegKUDFl0URa2OHHBZieoHvLmZBDh0mWfCALf5gAJl88Q2z3D7/tj9Rxko/f6j1ZFuEFKXpN8bseNlCMugPEPNWXq31oSOa47Fj/Rwb/a4nRo5nnOgdnlUsxZNTSIqouy9TEv2hATHqCwVeD5dBcLxezL8YUkNS01qdMjIt4iUabHrLVOXCsUUpUp2SwcgVWqWpJGqFYlydMLkTUHlE1QpXKi7SmGpaY01yrH45RF7CLLpcGfaPQQ1cTENKGR9MwAo1NTEp649ePrNtJpYEMmekYeMsp7x9BtTNUfA7OcGY2pD2W6NKGeMrD/VzACbW+4RqsauluTsjn611GQb2mpJbD1UcYpxQR+/THGhUcS01CD0+6u2GuzjY3U4apQZPVWGAUChBuTTMDyyV6Xf8NhqqN5dXKDsaFUVxg2TrLwGAJMabC/RFhGCkk5DE55RXB0rbmjkcwSf6DUb9rx8OG4sZe03ACzV8D7iV/EWgZE7cDIcA3Dg1LjyXhHgbi/CT3OXNy0KsN6WMgPBgpX6JpnPlEOwWd9o+HHrQI2Gp9W5AI2eEDwsIWGrUfC/y5LUzfBVQviI86lf5JoFOIHeB+j3tHMPEy6na2+9y/gKXd44t2Sb7EfufshmB/Yt9jxOBtRYeHqwyKppALCocfGnrjaYhnbr7qgx7MT2lsrax9dvgdVY9Kvu0CMjNAAF1bWl/k7vQ+1EwSXfVTpuJ1cGagBObkd+obv3IeBvLpho78MAgLpbDp+KfZLdsAHYp14ZgXbFokcq7m6XxGDyAVqqHPrRbl5l87P8z6V5olajq9vmiVWreaLHavhvPRVTXDCyyh7AgrmT05A6Lejq4O27wgnS2BKjp8jySG+VHl5fHMXPtV6/ZYf/AA== \ No newline at end of file diff --git a/src/MiniExcel.sln b/src/MiniExcel.sln index 82628d3..45057c6 100644 --- a/src/MiniExcel.sln +++ b/src/MiniExcel.sln @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\appveyor.yml = ..\appveyor.yml ..\LICENSE.md = ..\LICENSE.md ..\README.md = ..\README.md + ..\README.zh-Hans.md = ..\README.zh-Hans.md + ..\README.zh-tw.md = ..\README.zh-tw.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CC1E0601-AEC9-42D7-8F6A-3FB3939EED16}" @@ -25,7 +27,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{3E370222-8 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiniExcelTests", "..\tests\MiniExcelTests\MiniExcelTests.csproj", "{77F2C86B-0F17-4370-AB38-A089F9DF4ED5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniExcel.Benchmarks", "..\benchmarks\MiniExcel.Benchmarks\MiniExcel.Benchmarks.csproj", "{1888285A-B130-48D5-A628-DC85B623FAB8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiniExcel.Benchmarks", "..\benchmarks\MiniExcel.Benchmarks\MiniExcel.Benchmarks.csproj", "{1888285A-B130-48D5-A628-DC85B623FAB8}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{77A8A169-168B-457F-AB5F-48F30D6BB33C}" EndProject