mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-11-29 18:38:08 +08:00
Update README (#618)
* Update README * Link PackageReadmeFile * Signed commit
This commit is contained in:
parent
00a445c6bd
commit
6bcf5dd89d
419
README.md
419
README.md
@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
<p><a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/v/MiniExcel.svg" alt="NuGet"></a> <a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/dt/MiniExcel.svg" alt=""></a>
|
||||
<p><a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/v/MiniExcel.svg" alt="NuGet"></a> <a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/dt/MiniExcel.svg" alt=""></a>
|
||||
<a href="https://ci.appveyor.com/project/shps951023/miniexcel/branch/master"><img src="https://ci.appveyor.com/api/projects/status/b2vustrwsuqx45f4/branch/master?svg=true" alt="Build status"></a>
|
||||
<a href="https://gitee.com/dotnetchina/MiniExcel"><img src="https://gitee.com/dotnetchina/MiniExcel/badge/star.svg" alt="star"></a> <a href="https://github.com/shps951023/MiniExcel" rel="nofollow"><img src="https://img.shields.io/github/stars/shps951023/MiniExcel?logo=github" alt="GitHub stars"></a>
|
||||
<a href="https://gitee.com/dotnetchina/MiniExcel"><img src="https://gitee.com/dotnetchina/MiniExcel/badge/star.svg" alt="star"></a> <a href="https://github.com/shps951023/MiniExcel" rel="nofollow"><img src="https://img.shields.io/github/stars/shps951023/MiniExcel?logo=github" alt="GitHub stars"></a>
|
||||
<a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/badge/.NET-%3E%3D%204.5-red.svg" alt="version"></a>
|
||||
</p>
|
||||
</div>
|
||||
@ -15,7 +15,7 @@
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
Your <a href="https://github.com/shps951023/MiniExcel">Star</a> and <a href="https://miniexcel.github.io">Donate</a> can make MiniExcel better
|
||||
Your <a href="https://github.com/shps951023/MiniExcel">Star</a> and <a href="https://miniexcel.github.io">Donate</a> can make MiniExcel better
|
||||
</div>
|
||||
|
||||
---
|
||||
@ -47,7 +47,7 @@ At present, most popular frameworks need to load all the data into the memory to
|
||||
|
||||
- [Examples](#getstart5)
|
||||
|
||||
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
@ -57,7 +57,7 @@ You can install the package [from NuGet](https://www.nuget.org/packages/MiniExce
|
||||
|
||||
Please Check [Release Notes](docs)
|
||||
|
||||
### TODO
|
||||
### TODO
|
||||
|
||||
Please Check [TODO](https://github.com/shps951023/MiniExcel/projects/1?fullscreen=true)
|
||||
|
||||
@ -69,14 +69,14 @@ Benchmarks logic can be found in [MiniExcel.Benchmarks](benchmarks/MiniExcel.Be
|
||||
dotnet run -p .\benchmarks\MiniExcel.Benchmarks\ -c Release -f netcoreapp3.1 -- -f * --join
|
||||
```
|
||||
|
||||
Output from the latest run is :
|
||||
Output from the latest run is :
|
||||
|
||||
```bash
|
||||
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
|
||||
IterationCount=3 LaunchCount=3 WarmupCount=3
|
||||
```
|
||||
|
||||
Benchmark History : [Link](https://github.com/shps951023/MiniExcel/issues/276)
|
||||
@ -85,7 +85,7 @@ Benchmark History : [Link](https://github.com/shps951023/MiniExcel/issues/276)
|
||||
|
||||
#### Import/Query Excel
|
||||
|
||||
Logic : [**Test1,000,000x10.xlsx**](benchmarks/MiniExcel.Benchmarks/Test1%2C000%2C000x10.xlsx) as performance test basic file, 1,000,000 rows * 10 columns "HelloWorld" cells, 23 MB file size
|
||||
Logic : [**Test1,000,000x10.xlsx**](benchmarks/MiniExcel.Benchmarks/Test1%2C000%2C000x10.xlsx) as performance test basic file, 1,000,000 rows * 10 columns "HelloWorld" cells, 23 MB file size
|
||||
|
||||
|
||||
| Library | Method | Max Memory Usage | Mean |
|
||||
@ -101,7 +101,7 @@ Logic : [**Test1,000,000x10.xlsx**](benchmarks/MiniExcel.Benchmarks/Test1%2C000%
|
||||
| ClosedXml | 'ClosedXml QueryFirst' | 2,158 MB | 66.18897 sec |
|
||||
| ClosedXml | 'ClosedXml Query' | 2,184 MB | 191.43412 sec |
|
||||
|
||||
#### Export/Create Excel
|
||||
#### Export/Create Excel
|
||||
|
||||
Logic : create a total of 10,000,000 "HelloWorld" excel
|
||||
|
||||
@ -151,11 +151,11 @@ using (var stream = File.OpenRead(path))
|
||||
|
||||
var rows = MiniExcel.Query(path).ToList();
|
||||
|
||||
// or
|
||||
// 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);
|
||||
@ -165,9 +165,9 @@ using (var stream = File.OpenRead(path))
|
||||
|
||||
#### 3. Execute a query with first header row [[Try it]](https://dotnetfiddle.net/w5WD1J)
|
||||
|
||||
note : same column name use last right one
|
||||
note : same column name use last right one
|
||||
|
||||
Input Excel :
|
||||
Input Excel :
|
||||
|
||||
| Column1 | Column2 |
|
||||
| -------- | -------- |
|
||||
@ -208,7 +208,7 @@ using (var stream = File.OpenRead(path))
|
||||
}
|
||||
```
|
||||
|
||||
Performance between MiniExcel/ExcelDataReader/ClosedXML/EPPlus
|
||||
Performance between MiniExcel/ExcelDataReader/ClosedXML/EPPlus
|
||||
![queryfirst](https://user-images.githubusercontent.com/12729184/111072392-6037a900-8515-11eb-9693-5ce2dad1e460.gif)
|
||||
|
||||
#### 5. Query by sheet name
|
||||
@ -229,7 +229,7 @@ foreach (var sheetName in sheetNames)
|
||||
}
|
||||
```
|
||||
|
||||
#### 7. Get Columns
|
||||
#### 7. Get Columns
|
||||
|
||||
```csharp
|
||||
var columns = MiniExcel.GetColumns(path); // e.g result : ["A","B"...]
|
||||
@ -237,7 +237,7 @@ var columns = MiniExcel.GetColumns(path); // e.g result : ["A","B"...]
|
||||
var cnt = columns.Count; // get column count
|
||||
```
|
||||
|
||||
#### 8. Dynamic Query cast row to `IDictionary<string,object>`
|
||||
#### 8. Dynamic Query cast row to `IDictionary<string,object>`
|
||||
|
||||
```csharp
|
||||
foreach(IDictionary<string,object> row in MiniExcel.Query(path))
|
||||
@ -245,8 +245,8 @@ foreach(IDictionary<string,object> row in MiniExcel.Query(path))
|
||||
//..
|
||||
}
|
||||
|
||||
// or
|
||||
var rows = MiniExcel.Query(path).Cast<IDictionary<string,object>>();
|
||||
// or
|
||||
var rows = MiniExcel.Query(path).Cast<IDictionary<string,object>>();
|
||||
```
|
||||
|
||||
|
||||
@ -273,18 +273,18 @@ MiniExcel.Query(path,useHeaderRow:true,startCell:"B3")
|
||||
|
||||
|
||||
|
||||
#### 11. Fill Merged Cells
|
||||
#### 11. Fill Merged Cells
|
||||
|
||||
Note: The efficiency is slower compared to `not using merge fill`
|
||||
Note: The efficiency is slower compared to `not using merge fill`
|
||||
|
||||
Reason: The OpenXml standard puts mergeCells at the bottom of the file, which leads to the need to foreach the sheetxml twice
|
||||
|
||||
```csharp
|
||||
var config = new OpenXmlConfiguration()
|
||||
{
|
||||
FillMergedCells = true
|
||||
};
|
||||
var rows = MiniExcel.Query(path, configuration: config);
|
||||
var config = new OpenXmlConfiguration()
|
||||
{
|
||||
FillMergedCells = true
|
||||
};
|
||||
var rows = MiniExcel.Query(path, configuration: config);
|
||||
```
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/117973630-3527d500-b35f-11eb-95c3-bde255f8114e.png)
|
||||
@ -295,7 +295,7 @@ support variable length and width multi-row and column filling
|
||||
|
||||
#### 12. Reading big file by disk-base cache (Disk-Base Cache - SharedString)
|
||||
|
||||
If the SharedStrings size exceeds 5 MB, MiniExcel default will use local disk cache, e.g, [10x100000.xlsx](https://github.com/MiniExcel/MiniExcel/files/8403819/NotDuplicateSharedStrings_10x100000.xlsx)(one million rows data), when disable disk cache the maximum memory usage is 195MB, but able disk cache only needs 65MB. Note, this optimization needs some efficiency cost, so this case will increase reading time from 7.4 seconds to 27.2 seconds, If you don't need it that you can disable disk cache with the following code:
|
||||
If the SharedStrings size exceeds 5 MB, MiniExcel default will use local disk cache, e.g, [10x100000.xlsx](https://github.com/MiniExcel/MiniExcel/files/8403819/NotDuplicateSharedStrings_10x100000.xlsx)(one million rows data), when disable disk cache the maximum memory usage is 195MB, but able disk cache only needs 65MB. Note, this optimization needs some efficiency cost, so this case will increase reading time from 7.4 seconds to 27.2 seconds, If you don't need it that you can disable disk cache with the following code:
|
||||
|
||||
```csharp
|
||||
var config = new OpenXmlConfiguration { EnableSharedStringCache = false };
|
||||
@ -327,7 +327,7 @@ MiniExcel.Query(path, configuration: config);
|
||||
|
||||
2. MiniExcel support parameter IEnumerable Deferred Execution, If you want to use least memory, please do not call methods such as ToList
|
||||
|
||||
e.g : ToList or not memory usage
|
||||
e.g : ToList or not memory usage
|
||||
![image](https://user-images.githubusercontent.com/12729184/112587389-752b0b00-8e38-11eb-8a52-cfb76c57e5eb.png)
|
||||
|
||||
|
||||
@ -353,7 +353,7 @@ var values = new List<Dictionary<string, object>>()
|
||||
MiniExcel.SaveAs(path, values);
|
||||
```
|
||||
|
||||
Create File Result :
|
||||
Create File Result :
|
||||
|
||||
| Column1 | Column2 |
|
||||
| -------- | -------- |
|
||||
@ -361,7 +361,7 @@ Create File Result :
|
||||
| Github | 2 |
|
||||
|
||||
|
||||
#### 3. IDataReader
|
||||
#### 3. IDataReader
|
||||
- `Recommended`, it can avoid to load all data into memory
|
||||
```csharp
|
||||
MiniExcel.SaveAs(path, reader);
|
||||
@ -388,7 +388,7 @@ using (var cnn = Connection)
|
||||
|
||||
- `Not recommended`, it will load all data into memory
|
||||
|
||||
- DataTable use Caption for column name first, then use columname
|
||||
- DataTable use Caption for column name first, then use columname
|
||||
|
||||
```csharp
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||
@ -420,7 +420,7 @@ using (var connection = GetConnection(connectionString))
|
||||
}
|
||||
```
|
||||
|
||||
Below code will load all data into memory
|
||||
Below code will load all data into memory
|
||||
|
||||
```csharp
|
||||
using (var connection = GetConnection(connectionString))
|
||||
@ -487,7 +487,7 @@ MiniExcel.SaveAs(path, sheets);
|
||||
|
||||
#### 8. TableStyles Options
|
||||
|
||||
Default style
|
||||
Default style
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/138234373-cfa97109-b71f-4711-b7f5-0eaaa4a0a3a6.png)
|
||||
|
||||
@ -504,9 +504,9 @@ MiniExcel.SaveAs(path, value,configuration:config);
|
||||
![image](https://user-images.githubusercontent.com/12729184/118784917-f3e57700-b8c2-11eb-8718-8d955b1bc197.png)
|
||||
|
||||
|
||||
#### 9. AutoFilter
|
||||
#### 9. AutoFilter
|
||||
|
||||
Since v0.19.0 `OpenXmlConfiguration.AutoFilter` can en/unable AutoFilter , default value is `true`, and setting AutoFilter way:
|
||||
Since v0.19.0 `OpenXmlConfiguration.AutoFilter` can en/unable AutoFilter , default value is `true`, and setting AutoFilter way:
|
||||
|
||||
```csharp
|
||||
MiniExcel.SaveAs(path, value, configuration: new OpenXmlConfiguration() { AutoFilter = false });
|
||||
@ -548,7 +548,7 @@ You can use @mergelimit to limit boundaries of merging cells vertically.
|
||||
|
||||
```csharp
|
||||
var mergedFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
|
||||
|
||||
|
||||
var path = @"../../../../../samples/xlsx/TestMergeWithTag.xlsx";
|
||||
|
||||
MiniExcel.MergeSameCells(mergedFilePath, path);
|
||||
@ -556,7 +556,7 @@ MiniExcel.MergeSameCells(mergedFilePath, path);
|
||||
|
||||
```csharp
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
|
||||
var path = @"../../../../../samples/xlsx/TestMergeWithTag.xlsx";
|
||||
|
||||
memoryStream.MergeSameCells(path);
|
||||
@ -653,13 +653,13 @@ Works for null and DBNull values.
|
||||
|
||||
#### 1. Basic Fill
|
||||
|
||||
Template:
|
||||
Template:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114537556-ed8d2b00-9c84-11eb-8303-a69f62c41e5b.png)
|
||||
|
||||
Result:
|
||||
Result:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114537490-d8180100-9c84-11eb-8c69-db58692f3a85.png)
|
||||
|
||||
Code:
|
||||
Code:
|
||||
```csharp
|
||||
// 1. By POCO
|
||||
var value = new
|
||||
@ -689,13 +689,13 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
> Note1: Use the first IEnumerable of the same column as the basis for filling list
|
||||
|
||||
Template:
|
||||
Template:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114564652-14f2f080-9ca3-11eb-831f-09e3fedbc5fc.png)
|
||||
|
||||
Result:
|
||||
Result:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114564204-b2015980-9ca2-11eb-900d-e21249f93f7c.png)
|
||||
|
||||
Code:
|
||||
Code:
|
||||
```csharp
|
||||
//1. By POCO
|
||||
var value = new
|
||||
@ -732,11 +732,11 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
> Note: Support multi-sheets and using same varible
|
||||
|
||||
Template:
|
||||
Template:
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114565255-acf0da00-9ca3-11eb-8a7f-8131b2265ae8.png)
|
||||
|
||||
Result:
|
||||
Result:
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114565329-bf6b1380-9ca3-11eb-85e3-3969e8bf6378.png)
|
||||
|
||||
@ -784,9 +784,9 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
|
||||
|
||||
#### 5. Cell value auto mapping type
|
||||
#### 5. Cell value auto mapping type
|
||||
|
||||
Template
|
||||
Template
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114802504-64830a80-9dd0-11eb-8d56-8e8c401b3ace.png)
|
||||
|
||||
@ -794,7 +794,7 @@ Result
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114802419-43221e80-9dd0-11eb-9ffe-a2ce34fe7076.png)
|
||||
|
||||
Class
|
||||
Class
|
||||
|
||||
```csharp
|
||||
public class Poco
|
||||
@ -829,12 +829,12 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
#### 6. Example : List Github Projects
|
||||
|
||||
Template
|
||||
Template
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/115068623-12073280-9f25-11eb-9124-f4b3efcdb2a7.png)
|
||||
|
||||
|
||||
Result
|
||||
Result
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/115068639-1a5f6d80-9f25-11eb-9f45-27c434d19a78.png)
|
||||
|
||||
@ -989,7 +989,7 @@ public class ExcelAttributeDemo
|
||||
[ExcelIgnore]
|
||||
public string Test3 { get; set; }
|
||||
[ExcelColumnIndex("I")] // system will convert "I" to 8 index
|
||||
public string Test4 { get; set; }
|
||||
public string Test4 { get; set; }
|
||||
public string Test5 { get; } //wihout set will ignore
|
||||
public string Test6 { get; private set; } //un-public set will ignore
|
||||
[ExcelColumnIndex(3)] // start with 0
|
||||
@ -1071,7 +1071,7 @@ public class Dto
|
||||
|
||||
#### 5. System.ComponentModel.DisplayNameAttribute = ExcelColumnName.excelColumnNameAttribute
|
||||
|
||||
Since 1.24.0, system supports System.ComponentModel.DisplayNameAttribute = ExcelColumnName.excelColumnNameAttribute
|
||||
Since 1.24.0, system supports System.ComponentModel.DisplayNameAttribute = ExcelColumnName.excelColumnNameAttribute
|
||||
|
||||
```C#
|
||||
public class TestIssueI4TXGTDto
|
||||
@ -1087,9 +1087,9 @@ public class TestIssueI4TXGTDto
|
||||
|
||||
|
||||
|
||||
#### 6. ExcelColumnAttribute
|
||||
#### 6. ExcelColumnAttribute
|
||||
|
||||
Since V1.26.0, multiple attributes can be simplified like :
|
||||
Since V1.26.0, multiple attributes can be simplified like :
|
||||
```csharp
|
||||
public class TestIssueI4ZYUUDto
|
||||
{
|
||||
@ -1102,13 +1102,13 @@ Since V1.26.0, multiple attributes can be simplified like :
|
||||
|
||||
|
||||
|
||||
#### 7. DynamicColumnAttribute
|
||||
#### 7. DynamicColumnAttribute
|
||||
|
||||
Since V1.26.0, we can set the attributes of Column dynamically
|
||||
```csharp
|
||||
var config = new OpenXmlConfiguration
|
||||
{
|
||||
DynamicColumns = new DynamicExcelColumn[] {
|
||||
DynamicColumns = new DynamicExcelColumn[] {
|
||||
new DynamicExcelColumn("id"){Ignore=true},
|
||||
new DynamicExcelColumn("name"){Index=1,Width=10},
|
||||
new DynamicExcelColumn("createdate"){Index=0,Format="yyyy-MM-dd",Width=15},
|
||||
@ -1174,7 +1174,7 @@ v1.28.0 support CSV insert N rows data after last row
|
||||
MiniExcel.SaveAs(path, value);
|
||||
}
|
||||
// Insert 1 rows after last
|
||||
{
|
||||
{
|
||||
var value = new { ID=3,Name = "Mike", InDate = new DateTime(2021, 04, 23) };
|
||||
MiniExcel.Insert(path, value);
|
||||
}
|
||||
@ -1230,7 +1230,7 @@ stream.Query(excelType:ExcelType.XLSX);
|
||||
The default is `,` as the separator, you can modify the `Seperator` property for customization
|
||||
|
||||
```csharp
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
{
|
||||
Seperator=';'
|
||||
};
|
||||
@ -1255,7 +1255,7 @@ var rows = MiniExcel.Query(path, configuration: config).ToList();
|
||||
The default is `\r\n` as the newline character, you can modify the `NewLine` property for customization
|
||||
|
||||
```csharp
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
{
|
||||
NewLine='\n'
|
||||
};
|
||||
@ -1300,7 +1300,7 @@ var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
### DataReader
|
||||
|
||||
#### 1. GetReader
|
||||
Since 1.23.0, you can GetDataReader
|
||||
Since 1.23.0, you can GetDataReader
|
||||
|
||||
```csharp
|
||||
using (var reader = MiniExcel.GetReader(path,true))
|
||||
@ -1325,13 +1325,13 @@ Since 1.23.0, you can GetDataReader
|
||||
public static Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null)
|
||||
public static Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
|
||||
public static Task<IEnumerable<dynamic>> QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<IDictionary<string, object>>> QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, string templatePath, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value)
|
||||
public static Task<DataTable> QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
```
|
||||
|
||||
@ -1354,7 +1354,7 @@ public class Dto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public I49RYZUserType UserType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type
|
||||
{
|
||||
@ -1376,11 +1376,16 @@ Since 1.30.0 version support excel Description to Enum , thanks @KaneLeung
|
||||
```csharp
|
||||
MiniExcel.ConvertXlsxToCsv(xlsxPath, csvPath);
|
||||
MiniExcel.ConvertXlsxToCsv(xlsxStream, csvStream);
|
||||
MiniExcel.ConvertXlsxToCsv(csvPath, xlsxPath);
|
||||
MiniExcel.ConvertXlsxToCsv(csvStream, xlsxStream);
|
||||
MiniExcel.ConvertCsvToXlsx(csvPath, xlsxPath);
|
||||
MiniExcel.ConvertCsvToXlsx(csvStream, xlsxStream);
|
||||
```
|
||||
```csharp
|
||||
using (var excelStream = new FileStream(path: filePath, FileMode.Open, FileAccess.Read))
|
||||
using (var csvStream = new MemoryStream())
|
||||
{
|
||||
MiniExcel.ConvertXlsxToCsv(excelStream, csvStream);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 3. Custom CultureInfo
|
||||
|
||||
@ -1389,7 +1394,7 @@ Since 1.22.0, you can custom CultureInfo like below, system default `CultureInfo
|
||||
```csharp
|
||||
var config = new CsvConfiguration()
|
||||
{
|
||||
Culture = new CultureInfo("fr-FR"),
|
||||
Culture = new CultureInfo("fr-FR"),
|
||||
};
|
||||
MiniExcel.SaveAs(path, value, configuration: config);
|
||||
|
||||
@ -1433,10 +1438,10 @@ using (var connection = new SQLiteConnection(connectionString))
|
||||
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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1572,19 +1577,19 @@ public class ApiController : Controller
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var rows = MiniExcel.Query(path);
|
||||
|
||||
Console.WriteLine("==== No.1 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:1));
|
||||
Console.WriteLine("==== No.50 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:50));
|
||||
Console.WriteLine("==== No.5000 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:5000));
|
||||
var rows = MiniExcel.Query(path);
|
||||
|
||||
Console.WriteLine("==== No.1 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:1));
|
||||
Console.WriteLine("==== No.50 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:50));
|
||||
Console.WriteLine("==== No.5000 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:5000));
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Page<T>(IEnumerable<T> en, int pageSize, int page)
|
||||
{
|
||||
return en.Skip(page * pageSize).Take(pageSize);
|
||||
return en.Skip(page * pageSize).Take(pageSize);
|
||||
}
|
||||
```
|
||||
|
||||
@ -1621,70 +1626,70 @@ Like the example, create a method to handle i18n and permission management, and
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var value = new Order[] {
|
||||
new Order(){OrderNo = "SO01",CustomerID="C001",ProductID="P001",Qty=100,Amt=500},
|
||||
new Order(){OrderNo = "SO02",CustomerID="C002",ProductID="P002",Qty=300,Amt=400},
|
||||
};
|
||||
var value = new Order[] {
|
||||
new Order(){OrderNo = "SO01",CustomerID="C001",ProductID="P001",Qty=100,Amt=500},
|
||||
new Order(){OrderNo = "SO02",CustomerID="C002",ProductID="P002",Qty=300,Amt=400},
|
||||
};
|
||||
|
||||
Console.WriteLine("en-Us and Sales role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "en-US";
|
||||
var role = "Sales";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
Console.WriteLine("en-Us and Sales role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "en-US";
|
||||
var role = "Sales";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
|
||||
Console.WriteLine("zh-CN and PMC role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "zh-CN";
|
||||
var role = "PMC";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
Console.WriteLine("zh-CN and PMC role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "zh-CN";
|
||||
var role = "PMC";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Dictionary<string, object>> GetOrders(string lang, string role, Order[] orders)
|
||||
{
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var newOrder = new Dictionary<string, object>();
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var newOrder = new Dictionary<string, object>();
|
||||
|
||||
if (lang == "zh-CN")
|
||||
{
|
||||
newOrder.Add("客户编号", order.CustomerID);
|
||||
newOrder.Add("订单编号", order.OrderNo);
|
||||
newOrder.Add("产品编号", order.ProductID);
|
||||
newOrder.Add("数量", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("价格", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else if (lang == "en-US")
|
||||
{
|
||||
newOrder.Add("Customer ID", order.CustomerID);
|
||||
newOrder.Add("Order No", order.OrderNo);
|
||||
newOrder.Add("Product ID", order.ProductID);
|
||||
newOrder.Add("Quantity", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("Amount", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException($"lang {lang} wrong");
|
||||
}
|
||||
}
|
||||
if (lang == "zh-CN")
|
||||
{
|
||||
newOrder.Add("客户编号", order.CustomerID);
|
||||
newOrder.Add("订单编号", order.OrderNo);
|
||||
newOrder.Add("产品编号", order.ProductID);
|
||||
newOrder.Add("数量", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("价格", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else if (lang == "en-US")
|
||||
{
|
||||
newOrder.Add("Customer ID", order.CustomerID);
|
||||
newOrder.Add("Order No", order.OrderNo);
|
||||
newOrder.Add("Product ID", order.ProductID);
|
||||
newOrder.Add("Quantity", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("Amount", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException($"lang {lang} wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Order
|
||||
{
|
||||
public string OrderNo { get; set; }
|
||||
public string CustomerID { get; set; }
|
||||
public decimal Qty { get; set; }
|
||||
public string ProductID { get; set; }
|
||||
public decimal Amt { get; set; }
|
||||
public string OrderNo { get; set; }
|
||||
public string CustomerID { get; set; }
|
||||
public decimal Qty { get; set; }
|
||||
public string ProductID { get; set; }
|
||||
public decimal Amt { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
@ -1743,38 +1748,38 @@ No, the image test has 1 million rows*10 columns of data, the maximum memory usa
|
||||
|
||||
#### Q. How does Query use integer indexs?
|
||||
|
||||
The default index of Query is the string Key: A,B,C.... If you want to change to numeric index, please create the following method to convert
|
||||
The default index of Query is the string Key: A,B,C.... If you want to change to numeric index, please create the following method to convert
|
||||
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var path = @"D:\git\MiniExcel\samples\xlsx\TestTypeMapping.xlsx";
|
||||
var rows = MiniExcel.Query(path,true);
|
||||
foreach (var r in ConvertToIntIndexRows(rows))
|
||||
{
|
||||
Console.Write($"column 0 : {r[0]} ,column 1 : {r[1]}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
var path = @"D:\git\MiniExcel\samples\xlsx\TestTypeMapping.xlsx";
|
||||
var rows = MiniExcel.Query(path,true);
|
||||
foreach (var r in ConvertToIntIndexRows(rows))
|
||||
{
|
||||
Console.Write($"column 0 : {r[0]} ,column 1 : {r[1]}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Dictionary<int, object>> ConvertToIntIndexRows(IEnumerable<object> rows)
|
||||
{
|
||||
ICollection<string> keys = null;
|
||||
var isFirst = true;
|
||||
foreach (IDictionary<string,object> r in rows)
|
||||
{
|
||||
if(isFirst)
|
||||
{
|
||||
keys = r.Keys;
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
var dic = new Dictionary<int, object>();
|
||||
var index = 0;
|
||||
foreach (var key in keys)
|
||||
dic[index++] = r[key];
|
||||
yield return dic;
|
||||
}
|
||||
ICollection<string> keys = null;
|
||||
var isFirst = true;
|
||||
foreach (IDictionary<string,object> r in rows)
|
||||
{
|
||||
if(isFirst)
|
||||
{
|
||||
keys = r.Keys;
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
var dic = new Dictionary<int, object>();
|
||||
var index = 0;
|
||||
foreach (var key in keys)
|
||||
dic[index++] = r[key];
|
||||
yield return dic;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1797,77 +1802,77 @@ MiniExcel can be used with `LINQ TakeWhile` to stop foreach iterator.
|
||||
![image](https://user-images.githubusercontent.com/12729184/137873865-7107d8f5-eb59-42db-903a-44e80589f1b2.png)
|
||||
|
||||
|
||||
IEnumerable :
|
||||
IEnumerable :
|
||||
|
||||
```csharp
|
||||
public static IEnumerable<dynamic> QueryWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
|
||||
{
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string,object> row in rows)
|
||||
{
|
||||
if(row.Keys.Any(key=>row[key]!=null))
|
||||
yield return row;
|
||||
}
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string,object> row in rows)
|
||||
{
|
||||
if(row.Keys.Any(key=>row[key]!=null))
|
||||
yield return row;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
DataTable :
|
||||
DataTable :
|
||||
|
||||
```csharp
|
||||
public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
|
||||
{
|
||||
if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/
|
||||
sheetName = stream.GetSheetNames().First();
|
||||
if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/
|
||||
sheetName = stream.GetSheetNames().First();
|
||||
|
||||
var dt = new DataTable(sheetName);
|
||||
var first = true;
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string, object> row in rows)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
var dt = new DataTable(sheetName);
|
||||
var first = true;
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string, object> row in rows)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var column = new DataColumn(key, typeof(object)) { Caption = key };
|
||||
dt.Columns.Add(column);
|
||||
}
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var column = new DataColumn(key, typeof(object)) { Caption = key };
|
||||
dt.Columns.Add(column);
|
||||
}
|
||||
|
||||
dt.BeginLoadData();
|
||||
first = false;
|
||||
}
|
||||
dt.BeginLoadData();
|
||||
first = false;
|
||||
}
|
||||
|
||||
var newRow = dt.NewRow();
|
||||
var isNull=true;
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var _v = row[key];
|
||||
if(_v!=null)
|
||||
isNull = false;
|
||||
newRow[key] = _v;
|
||||
}
|
||||
|
||||
if(!isNull)
|
||||
dt.Rows.Add(newRow);
|
||||
}
|
||||
var newRow = dt.NewRow();
|
||||
var isNull=true;
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var _v = row[key];
|
||||
if(_v!=null)
|
||||
isNull = false;
|
||||
newRow[key] = _v;
|
||||
}
|
||||
|
||||
dt.EndLoadData();
|
||||
return dt;
|
||||
if(!isNull)
|
||||
dt.Rows.Add(newRow);
|
||||
}
|
||||
|
||||
dt.EndLoadData();
|
||||
return dt;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### Q. How SaveAs(path,value) to replace exists file and without throwing "The file ...xlsx already exists error"
|
||||
#### Q. How SaveAs(path,value) to replace exists file and without throwing "The file ...xlsx already exists error"
|
||||
|
||||
|
||||
Please use Stream class to custom file creating logic, e.g:
|
||||
Please use Stream class to custom file creating logic, e.g:
|
||||
|
||||
```C#
|
||||
using (var stream = File.Create("Demo.xlsx"))
|
||||
MiniExcel.SaveAs(stream,value);
|
||||
using (var stream = File.Create("Demo.xlsx"))
|
||||
MiniExcel.SaveAs(stream,value);
|
||||
```
|
||||
|
||||
|
||||
@ -1875,7 +1880,7 @@ Please use Stream class to custom file creating logic, e.g:
|
||||
or, since V1.25.0, SaveAs support overwriteFile parameter for enable/unable overwriting exist file
|
||||
|
||||
```csharp
|
||||
MiniExcel.SaveAs(path, value, overwriteFile: true);
|
||||
MiniExcel.SaveAs(path, value, overwriteFile: true);
|
||||
```
|
||||
|
||||
|
||||
@ -1896,7 +1901,7 @@ or, since V1.25.0, SaveAs support overwriteFile parameter for enable/unable over
|
||||
|
||||
### Thanks
|
||||
|
||||
#### [Jetbrains](https://www.jetbrains.com/)
|
||||
#### [Jetbrains](https://www.jetbrains.com/)
|
||||
|
||||
![jetbrains-variant-2](https://user-images.githubusercontent.com/12729184/123997015-8456c180-da02-11eb-829a-aec476fe8e94.png)
|
||||
|
||||
@ -1904,9 +1909,9 @@ Thanks for providing a free All product IDE for this project ([License](https://
|
||||
|
||||
|
||||
|
||||
### Benefit
|
||||
### Benefit
|
||||
Link https://github.com/mini-software/MiniExcel/issues/560#issue-2080619180
|
||||
|
||||
### Contributors
|
||||
### Contributors
|
||||
|
||||
![](https://contrib.rocks/image?repo=shps951023/MiniExcel)
|
||||
|
374
README.zh-CN.md
374
README.zh-CN.md
@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
<p><a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/v/MiniExcel.svg" alt="NuGet"></a> <a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/dt/MiniExcel.svg" alt=""></a>
|
||||
<p><a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/v/MiniExcel.svg" alt="NuGet"></a> <a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/dt/MiniExcel.svg" alt=""></a>
|
||||
<a href="https://ci.appveyor.com/project/shps951023/miniexcel/branch/master"><img src="https://ci.appveyor.com/api/projects/status/b2vustrwsuqx45f4/branch/master?svg=true" alt="Build status"></a>
|
||||
<a href="https://gitee.com/dotnetchina/MiniExcel"><img src="https://gitee.com/dotnetchina/MiniExcel/badge/star.svg" alt="star"></a> <a href="https://github.com/shps951023/MiniExcel" rel="nofollow"><img src="https://img.shields.io/github/stars/shps951023/MiniExcel?logo=github" alt="GitHub stars"></a>
|
||||
<a href="https://gitee.com/dotnetchina/MiniExcel"><img src="https://gitee.com/dotnetchina/MiniExcel/badge/star.svg" alt="star"></a> <a href="https://github.com/shps951023/MiniExcel" rel="nofollow"><img src="https://img.shields.io/github/stars/shps951023/MiniExcel?logo=github" alt="GitHub stars"></a>
|
||||
<a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/badge/.NET-%3E%3D%204.5-red.svg" alt="version"></a>
|
||||
</p>
|
||||
</div>
|
||||
@ -40,7 +40,7 @@ MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工
|
||||
### 特点
|
||||
- 低内存耗用,避免OOM、频繁 Full GC 情况
|
||||
- 支持`即时`操作每行数据
|
||||
- 兼具搭配 LINQ 延迟查询特性,能办到低消耗、快速分页等复杂查询
|
||||
- 兼具搭配 LINQ 延迟查询特性,能办到低消耗、快速分页等复杂查询
|
||||
- 轻量,不需要安装 Microsoft Office、COM+,DLL小于150KB
|
||||
- 简便操作的 API 风格
|
||||
|
||||
@ -74,14 +74,14 @@ Benchmarks 逻辑可以在 [MiniExcel.Benchmarks](benchmarks/MiniExcel.Benchmar
|
||||
dotnet run -p .\benchmarks\MiniExcel.Benchmarks\ -c Release -f netcoreapp3.1 -- -f * --join
|
||||
```
|
||||
|
||||
最后一次运行规格、结果 :
|
||||
最后一次运行规格、结果 :
|
||||
|
||||
```bash
|
||||
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
|
||||
IterationCount=3 LaunchCount=3 WarmupCount=3
|
||||
```
|
||||
|
||||
Benchmark History : [Link](https://github.com/shps951023/MiniExcel/issues/276)
|
||||
@ -157,11 +157,11 @@ using (var stream = File.OpenRead(path))
|
||||
|
||||
var rows = MiniExcel.Query(path).ToList();
|
||||
|
||||
// or
|
||||
// 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);
|
||||
@ -171,9 +171,9 @@ using (var stream = File.OpenRead(path))
|
||||
|
||||
#### 3. 查询数据以第一行数据当Key [[Try it]](https://dotnetfiddle.net/w5WD1J)
|
||||
|
||||
注意 : 同名以右边数据为准
|
||||
注意 : 同名以右边数据为准
|
||||
|
||||
Input Excel :
|
||||
Input Excel :
|
||||
|
||||
| Column1 | Column2 |
|
||||
| -------- | -------- |
|
||||
@ -215,7 +215,7 @@ using (var stream = File.OpenRead(path))
|
||||
}
|
||||
```
|
||||
|
||||
与其他框架效率比较 :
|
||||
与其他框架效率比较 :
|
||||
|
||||
![queryfirst](https://user-images.githubusercontent.com/12729184/111072392-6037a900-8515-11eb-9693-5ce2dad1e460.gif)
|
||||
|
||||
@ -244,7 +244,7 @@ var columns = MiniExcel.GetColumns(path); // e.g result : ["A","B"...]
|
||||
|
||||
or
|
||||
|
||||
var columns = MiniExcel.GetColumns(path, useHeaderRow: true);
|
||||
var columns = MiniExcel.GetColumns(path, useHeaderRow: true);
|
||||
// e.g result : ["excel表实际的列名称","excel表实际的列名称"...]
|
||||
|
||||
var cnt = columns.Count; // get column count
|
||||
@ -258,8 +258,8 @@ foreach(IDictionary<string,object> row in MiniExcel.Query(path))
|
||||
//..
|
||||
}
|
||||
|
||||
// or
|
||||
var rows = MiniExcel.Query(path).Cast<IDictionary<string,object>>();
|
||||
// or
|
||||
var rows = MiniExcel.Query(path).Cast<IDictionary<string,object>>();
|
||||
```
|
||||
|
||||
#### 9. Query 读 Excel 返回 DataTable
|
||||
@ -282,15 +282,15 @@ MiniExcel.Query(path,useHeaderRow:true,startCell:"B3")
|
||||
|
||||
#### 11. 合并的单元格填充
|
||||
|
||||
注意 : 效率相对于`没有使用合并填充`来说差
|
||||
注意 : 效率相对于`没有使用合并填充`来说差
|
||||
底层原因 : OpenXml 标准将 mergeCells 放在文件最下方,导致需要遍历两次 sheetxml
|
||||
|
||||
```csharp
|
||||
var config = new OpenXmlConfiguration()
|
||||
{
|
||||
FillMergedCells = true
|
||||
};
|
||||
var rows = MiniExcel.Query(path, configuration: config);
|
||||
var config = new OpenXmlConfiguration()
|
||||
{
|
||||
FillMergedCells = true
|
||||
};
|
||||
var rows = MiniExcel.Query(path, configuration: config);
|
||||
```
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/117973630-3527d500-b35f-11eb-95c3-bde255f8114e.png)
|
||||
@ -333,7 +333,7 @@ MiniExcel.Query(path, configuration: config);
|
||||
1. 必须是非abstract 类别有公开无参数构造函数
|
||||
2. MiniExcel SaveAs 支援 `IEnumerable参数延迟查询`,除非必要请不要使用 ToList 等方法读取全部数据到内存
|
||||
|
||||
图片 : 是否呼叫 ToList 的内存差别
|
||||
图片 : 是否呼叫 ToList 的内存差别
|
||||
|
||||
#### ![image](https://user-images.githubusercontent.com/12729184/112587389-752b0b00-8e38-11eb-8a52-cfb76c57e5eb.png)1. 支持集合<匿名类别>或是<强型别> [[Try it]](https://dotnetfiddle.net/w5WD1J)
|
||||
|
||||
@ -358,7 +358,7 @@ var values = new List<Dictionary<string, object>>()
|
||||
MiniExcel.SaveAs(path, values);
|
||||
```
|
||||
|
||||
output :
|
||||
output :
|
||||
|
||||
| Column1 | Column2 |
|
||||
| --------- | ------- |
|
||||
@ -367,7 +367,7 @@ output :
|
||||
|
||||
|
||||
|
||||
#### 3. IDataReader
|
||||
#### 3. IDataReader
|
||||
|
||||
- 推荐使用,可以避免载入全部数据到内存
|
||||
|
||||
@ -513,7 +513,7 @@ MiniExcel.SaveAs(path, value,configuration:config);
|
||||
|
||||
#### 9. AutoFilter 筛选
|
||||
|
||||
从 0.19.0 支持,可藉由 OpenXmlConfiguration.AutoFilter 设定,预设为True。关闭 AutoFilter 方式 :
|
||||
从 0.19.0 支持,可藉由 OpenXmlConfiguration.AutoFilter 设定,预设为True。关闭 AutoFilter 方式 :
|
||||
|
||||
```csharp
|
||||
MiniExcel.SaveAs(path, value, configuration: new OpenXmlConfiguration() { AutoFilter = false });
|
||||
@ -554,7 +554,7 @@ MiniExcel.SaveAs(path, value);
|
||||
|
||||
```csharp
|
||||
var mergedFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
|
||||
|
||||
|
||||
var path = @"../../../../../samples/xlsx/TestMergeSameCells.xlsx";
|
||||
|
||||
MiniExcel.MergeSameCells(mergedFilePath, path);
|
||||
@ -562,7 +562,7 @@ MiniExcel.MergeSameCells(mergedFilePath, path);
|
||||
|
||||
```csharp
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
|
||||
var path = @"../../../../../samples/xlsx/TestMergeSameCells.xlsx";
|
||||
|
||||
memoryStream.MergeSameCells(path);
|
||||
@ -645,13 +645,13 @@ MiniExcel.SaveAs(@"C:\temp\Book1.xlsx", dt, configuration: configuration);
|
||||
|
||||
#### 1. 基本填充
|
||||
|
||||
模板:
|
||||
模板:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114537556-ed8d2b00-9c84-11eb-8303-a69f62c41e5b.png)
|
||||
|
||||
最终效果:
|
||||
最终效果:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114537490-d8180100-9c84-11eb-8c69-db58692f3a85.png)
|
||||
|
||||
代码:
|
||||
代码:
|
||||
```csharp
|
||||
// 1. By POCO
|
||||
var value = new
|
||||
@ -681,13 +681,13 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
> Note1: 同行从左往右以第一个 IEnumerableUse 当列表来源 (不支持同列多集合)
|
||||
|
||||
模板:
|
||||
模板:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114564652-14f2f080-9ca3-11eb-831f-09e3fedbc5fc.png)
|
||||
|
||||
最终效果:
|
||||
最终效果:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114564204-b2015980-9ca2-11eb-900d-e21249f93f7c.png)
|
||||
|
||||
代码:
|
||||
代码:
|
||||
|
||||
```csharp
|
||||
//1. By POCO
|
||||
@ -725,15 +725,15 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
> Note: 支持多 sheet 填充,并共用同一组参数
|
||||
|
||||
模板:
|
||||
模板:
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114565255-acf0da00-9ca3-11eb-8a7f-8131b2265ae8.png)
|
||||
|
||||
最终效果:
|
||||
最终效果:
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114565329-bf6b1380-9ca3-11eb-85e3-3969e8bf6378.png)
|
||||
|
||||
代码:
|
||||
代码:
|
||||
|
||||
```csharp
|
||||
// 1. By POCO
|
||||
@ -779,15 +779,15 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
#### 5. Cell 值自动类别对应
|
||||
|
||||
模板
|
||||
模板
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114802504-64830a80-9dd0-11eb-8d56-8e8c401b3ace.png)
|
||||
|
||||
最终效果
|
||||
最终效果
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114802419-43221e80-9dd0-11eb-9ffe-a2ce34fe7076.png)
|
||||
|
||||
类别
|
||||
类别
|
||||
|
||||
```csharp
|
||||
public class Poco
|
||||
@ -822,16 +822,16 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
#### 6. Example : 列出 Github 专案
|
||||
|
||||
模板
|
||||
模板
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/115068623-12073280-9f25-11eb-9124-f4b3efcdb2a7.png)
|
||||
|
||||
|
||||
最终效果
|
||||
最终效果
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/115068639-1a5f6d80-9f25-11eb-9f45-27c434d19a78.png)
|
||||
|
||||
代码
|
||||
代码
|
||||
|
||||
```csharp
|
||||
var projects = new[]
|
||||
@ -955,7 +955,7 @@ public class ExcelAttributeDemo
|
||||
[ExcelIgnore]
|
||||
public string Test3 { get; set; }
|
||||
[ExcelColumnIndex("I")] // 系统会自动转换"I"为第8列
|
||||
public string Test4 { get; set; }
|
||||
public string Test4 { get; set; }
|
||||
public string Test5 { get; } //系统会忽略此列
|
||||
public string Test6 { get; private set; } //set非公开,系统会忽略
|
||||
[ExcelColumnIndex(3)] // 从0开始索引
|
||||
@ -1047,7 +1047,7 @@ public class TestIssueI4TXGTDto
|
||||
}
|
||||
```
|
||||
|
||||
#### 6. ExcelColumnAttribute
|
||||
#### 6. ExcelColumnAttribute
|
||||
|
||||
从 1.26.0 版本开始,可以简化多Attribute写法
|
||||
```csharp
|
||||
@ -1060,13 +1060,13 @@ public class TestIssueI4TXGTDto
|
||||
}
|
||||
```
|
||||
|
||||
#### 7. DynamicColumnAttribute 动态设定 Column
|
||||
#### 7. DynamicColumnAttribute 动态设定 Column
|
||||
|
||||
从 1.26.0 版本开始,可以动态设定 Column 的属性
|
||||
```csharp
|
||||
var config = new OpenXmlConfiguration
|
||||
{
|
||||
DynamicColumns = new DynamicExcelColumn[] {
|
||||
DynamicColumns = new DynamicExcelColumn[] {
|
||||
new DynamicExcelColumn("id"){Ignore=true},
|
||||
new DynamicExcelColumn("name"){Index=1,Width=10},
|
||||
new DynamicExcelColumn("createdate"){Index=0,Format="yyyy-MM-dd",Width=15},
|
||||
@ -1097,7 +1097,7 @@ v1.28.0 开始支持 CSV 插入新增,在最后一行新增N笔数据
|
||||
MiniExcel.SaveAs(path, value);
|
||||
}
|
||||
// 最后一行新增一行数据
|
||||
{
|
||||
{
|
||||
var value = new { ID=3,Name = "Mike", InDate = new DateTime(2021, 04, 23) };
|
||||
MiniExcel.Insert(path, value);
|
||||
}
|
||||
@ -1149,7 +1149,7 @@ stream.Query(excelType:ExcelType.XLSX);
|
||||
预设以 `,` 作为分隔符,自定义请修改 `Seperator` 属性
|
||||
|
||||
```csharp
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
{
|
||||
Seperator=';'
|
||||
};
|
||||
@ -1163,7 +1163,7 @@ MiniExcel.SaveAs(path, values,configuration: config);
|
||||
预设以 `\r\n` 作为换行符,自定义请修改 `NewLine` 属性
|
||||
|
||||
```csharp
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
{
|
||||
NewLine='\n'
|
||||
};
|
||||
@ -1239,13 +1239,13 @@ MiniExcel.SaveAs(path, value,excelType:ExcelType.CSV, configuration: config);
|
||||
public static Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null)
|
||||
public static Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
|
||||
public static Task<IEnumerable<dynamic>> QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<IDictionary<string, object>>> QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, string templatePath, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value)
|
||||
public static Task<DataTable> QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
```
|
||||
|
||||
@ -1268,7 +1268,7 @@ public class Dto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Type UserType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type
|
||||
{
|
||||
@ -1292,12 +1292,16 @@ public enum Type
|
||||
```csharp
|
||||
MiniExcel.ConvertXlsxToCsv(xlsxPath, csvPath);
|
||||
MiniExcel.ConvertXlsxToCsv(xlsxStream, csvStream);
|
||||
MiniExcel.ConvertXlsxToCsv(csvPath, xlsxPath);
|
||||
MiniExcel.ConvertXlsxToCsv(csvStream, xlsxStream);
|
||||
MiniExcel.ConvertCsvToXlsx(csvPath, xlsxPath);
|
||||
MiniExcel.ConvertCsvToXlsx(csvStream, xlsxStream);
|
||||
```
|
||||
```csharp
|
||||
using (var excelStream = new FileStream(path: filePath, FileMode.Open, FileAccess.Read))
|
||||
using (var csvStream = new MemoryStream())
|
||||
{
|
||||
MiniExcel.ConvertXlsxToCsv(excelStream, csvStream);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 3. 自定义 CultureInfo
|
||||
|
||||
从 1.22.0 版本开始,可以使用以下代码自定义文化信息,系统预设 `CultureInfo.InvariantCulture`。
|
||||
@ -1305,7 +1309,7 @@ MiniExcel.ConvertXlsxToCsv(csvStream, xlsxStream);
|
||||
```csharp
|
||||
var config = new CsvConfiguration()
|
||||
{
|
||||
Culture = new CultureInfo("fr-FR"),
|
||||
Culture = new CultureInfo("fr-FR"),
|
||||
};
|
||||
MiniExcel.SaveAs(path, value, configuration: config);
|
||||
|
||||
@ -1481,19 +1485,19 @@ public class ApiController : Controller
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var rows = MiniExcel.Query(path);
|
||||
|
||||
Console.WriteLine("==== No.1 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:1));
|
||||
Console.WriteLine("==== No.50 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:50));
|
||||
Console.WriteLine("==== No.5000 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:5000));
|
||||
var rows = MiniExcel.Query(path);
|
||||
|
||||
Console.WriteLine("==== No.1 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:1));
|
||||
Console.WriteLine("==== No.50 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:50));
|
||||
Console.WriteLine("==== No.5000 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:5000));
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Page<T>(IEnumerable<T> en, int pageSize, int page)
|
||||
{
|
||||
return en.Skip(page * pageSize).Take(pageSize);
|
||||
return en.Skip(page * pageSize).Take(pageSize);
|
||||
}
|
||||
```
|
||||
|
||||
@ -1528,70 +1532,70 @@ response.End();
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var value = new Order[] {
|
||||
new Order(){OrderNo = "SO01",CustomerID="C001",ProductID="P001",Qty=100,Amt=500},
|
||||
new Order(){OrderNo = "SO02",CustomerID="C002",ProductID="P002",Qty=300,Amt=400},
|
||||
};
|
||||
var value = new Order[] {
|
||||
new Order(){OrderNo = "SO01",CustomerID="C001",ProductID="P001",Qty=100,Amt=500},
|
||||
new Order(){OrderNo = "SO02",CustomerID="C002",ProductID="P002",Qty=300,Amt=400},
|
||||
};
|
||||
|
||||
Console.WriteLine("en-Us and Sales role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "en-US";
|
||||
var role = "Sales";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
Console.WriteLine("en-Us and Sales role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "en-US";
|
||||
var role = "Sales";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
|
||||
Console.WriteLine("zh-CN and PMC role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "zh-CN";
|
||||
var role = "PMC";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
Console.WriteLine("zh-CN and PMC role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "zh-CN";
|
||||
var role = "PMC";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Dictionary<string, object>> GetOrders(string lang, string role, Order[] orders)
|
||||
{
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var newOrder = new Dictionary<string, object>();
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var newOrder = new Dictionary<string, object>();
|
||||
|
||||
if (lang == "zh-CN")
|
||||
{
|
||||
newOrder.Add("客户编号", order.CustomerID);
|
||||
newOrder.Add("订单编号", order.OrderNo);
|
||||
newOrder.Add("产品编号", order.ProductID);
|
||||
newOrder.Add("数量", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("价格", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else if (lang == "en-US")
|
||||
{
|
||||
newOrder.Add("Customer ID", order.CustomerID);
|
||||
newOrder.Add("Order No", order.OrderNo);
|
||||
newOrder.Add("Product ID", order.ProductID);
|
||||
newOrder.Add("Quantity", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("Amount", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException($"lang {lang} wrong");
|
||||
}
|
||||
}
|
||||
if (lang == "zh-CN")
|
||||
{
|
||||
newOrder.Add("客户编号", order.CustomerID);
|
||||
newOrder.Add("订单编号", order.OrderNo);
|
||||
newOrder.Add("产品编号", order.ProductID);
|
||||
newOrder.Add("数量", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("价格", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else if (lang == "en-US")
|
||||
{
|
||||
newOrder.Add("Customer ID", order.CustomerID);
|
||||
newOrder.Add("Order No", order.OrderNo);
|
||||
newOrder.Add("Product ID", order.ProductID);
|
||||
newOrder.Add("Quantity", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("Amount", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException($"lang {lang} wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Order
|
||||
{
|
||||
public string OrderNo { get; set; }
|
||||
public string CustomerID { get; set; }
|
||||
public decimal Qty { get; set; }
|
||||
public string ProductID { get; set; }
|
||||
public decimal Amt { get; set; }
|
||||
public string OrderNo { get; set; }
|
||||
public string CustomerID { get; set; }
|
||||
public decimal Qty { get; set; }
|
||||
public string ProductID { get; set; }
|
||||
public decimal Amt { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
@ -1648,33 +1652,33 @@ Query 预设索引为字串Key : A,B,C....,想要改为数字索引,请建
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var path = @"D:\git\MiniExcel\samples\xlsx\TestTypeMapping.xlsx";
|
||||
var rows = MiniExcel.Query(path,true);
|
||||
foreach (var r in ConvertToIntIndexRows(rows))
|
||||
{
|
||||
Console.Write($"column 0 : {r[0]} ,column 1 : {r[1]}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
var path = @"D:\git\MiniExcel\samples\xlsx\TestTypeMapping.xlsx";
|
||||
var rows = MiniExcel.Query(path,true);
|
||||
foreach (var r in ConvertToIntIndexRows(rows))
|
||||
{
|
||||
Console.Write($"column 0 : {r[0]} ,column 1 : {r[1]}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Dictionary<int, object>> ConvertToIntIndexRows(IEnumerable<object> rows)
|
||||
{
|
||||
ICollection<string> keys = null;
|
||||
var isFirst = true;
|
||||
foreach (IDictionary<string,object> r in rows)
|
||||
{
|
||||
if(isFirst)
|
||||
{
|
||||
keys = r.Keys;
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
var dic = new Dictionary<int, object>();
|
||||
var index = 0;
|
||||
foreach (var key in keys)
|
||||
dic[index++] = r[key];
|
||||
yield return dic;
|
||||
}
|
||||
ICollection<string> keys = null;
|
||||
var isFirst = true;
|
||||
foreach (IDictionary<string,object> r in rows)
|
||||
{
|
||||
if(isFirst)
|
||||
{
|
||||
keys = r.Keys;
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
var dic = new Dictionary<int, object>();
|
||||
var index = 0;
|
||||
foreach (var key in keys)
|
||||
dic[index++] = r[key];
|
||||
yield return dic;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1707,12 +1711,12 @@ IEnumerable版本
|
||||
```csharp
|
||||
public static IEnumerable<dynamic> QueryWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
|
||||
{
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string,object> row in rows)
|
||||
{
|
||||
if(row.Keys.Any(key=>row[key]!=null))
|
||||
yield return row;
|
||||
}
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string,object> row in rows)
|
||||
{
|
||||
if(row.Keys.Any(key=>row[key]!=null))
|
||||
yield return row;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1723,43 +1727,43 @@ DataTable版本
|
||||
```csharp
|
||||
public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
|
||||
{
|
||||
if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/
|
||||
sheetName = stream.GetSheetNames().First();
|
||||
if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/
|
||||
sheetName = stream.GetSheetNames().First();
|
||||
|
||||
var dt = new DataTable(sheetName);
|
||||
var first = true;
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string, object> row in rows)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
var dt = new DataTable(sheetName);
|
||||
var first = true;
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string, object> row in rows)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var column = new DataColumn(key, typeof(object)) { Caption = key };
|
||||
dt.Columns.Add(column);
|
||||
}
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var column = new DataColumn(key, typeof(object)) { Caption = key };
|
||||
dt.Columns.Add(column);
|
||||
}
|
||||
|
||||
dt.BeginLoadData();
|
||||
first = false;
|
||||
}
|
||||
dt.BeginLoadData();
|
||||
first = false;
|
||||
}
|
||||
|
||||
var newRow = dt.NewRow();
|
||||
var isNull=true;
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var _v = row[key];
|
||||
if(_v!=null)
|
||||
isNull = false;
|
||||
newRow[key] = _v;
|
||||
}
|
||||
|
||||
if(!isNull)
|
||||
dt.Rows.Add(newRow);
|
||||
}
|
||||
var newRow = dt.NewRow();
|
||||
var isNull=true;
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var _v = row[key];
|
||||
if(_v!=null)
|
||||
isNull = false;
|
||||
newRow[key] = _v;
|
||||
}
|
||||
|
||||
dt.EndLoadData();
|
||||
return dt;
|
||||
if(!isNull)
|
||||
dt.Rows.Add(newRow);
|
||||
}
|
||||
|
||||
dt.EndLoadData();
|
||||
return dt;
|
||||
}
|
||||
```
|
||||
|
||||
@ -1770,14 +1774,14 @@ public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useH
|
||||
请改以Stream自行管控Stream行为,如
|
||||
|
||||
```C#
|
||||
using (var stream = File.Create("Demo.xlsx"))
|
||||
MiniExcel.SaveAs(stream,value);
|
||||
using (var stream = File.Create("Demo.xlsx"))
|
||||
MiniExcel.SaveAs(stream,value);
|
||||
```
|
||||
|
||||
从V1.25.0版本开始,支持 overwriteFile 參數,方便調整是否要覆蓋已存在文件
|
||||
|
||||
```csharp
|
||||
MiniExcel.SaveAs(path, value, overwriteFile: true);
|
||||
MiniExcel.SaveAs(path, value, overwriteFile: true);
|
||||
```
|
||||
|
||||
|
||||
@ -1811,7 +1815,7 @@ public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useH
|
||||
目前收益 https://github.com/mini-software/MiniExcel/issues/560#issue-2080619180
|
||||
|
||||
|
||||
### Contributors
|
||||
### Contributors
|
||||
|
||||
![](https://contrib.rocks/image?repo=shps951023/MiniExcel)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
<p><a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/v/MiniExcel.svg" alt="NuGet"></a> <a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/dt/MiniExcel.svg" alt=""></a>
|
||||
<p><a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/v/MiniExcel.svg" alt="NuGet"></a> <a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/nuget/dt/MiniExcel.svg" alt=""></a>
|
||||
<a href="https://ci.appveyor.com/project/shps951023/miniexcel/branch/master"><img src="https://ci.appveyor.com/api/projects/status/b2vustrwsuqx45f4/branch/master?svg=true" alt="Build status"></a>
|
||||
<a href="https://gitee.com/dotnetchina/MiniExcel"><img src="https://gitee.com/dotnetchina/MiniExcel/badge/star.svg" alt="star"></a> <a href="https://github.com/shps951023/MiniExcel" rel="nofollow"><img src="https://img.shields.io/github/stars/shps951023/MiniExcel?logo=github" alt="GitHub stars"></a>
|
||||
<a href="https://gitee.com/dotnetchina/MiniExcel"><img src="https://gitee.com/dotnetchina/MiniExcel/badge/star.svg" alt="star"></a> <a href="https://github.com/shps951023/MiniExcel" rel="nofollow"><img src="https://img.shields.io/github/stars/shps951023/MiniExcel?logo=github" alt="GitHub stars"></a>
|
||||
<a href="https://www.nuget.org/packages/MiniExcel"><img src="https://img.shields.io/badge/.NET-%3E%3D%204.5-red.svg" alt="version"></a>
|
||||
</p>
|
||||
</div>
|
||||
@ -58,7 +58,7 @@ MiniExcel 簡單、高效避免OOM的.NET處理Excel查、寫、填充工具。
|
||||
|
||||
請查看 [Release Notes](docs)
|
||||
|
||||
### TODO
|
||||
### TODO
|
||||
|
||||
請查看 [TODO](https://github.com/shps951023/MiniExcel/projects/1?fullscreen=true)
|
||||
|
||||
@ -70,14 +70,14 @@ Benchmarks 邏輯可以在 [MiniExcel.Benchmarks](benchmarks/MiniExcel.Benchmar
|
||||
dotnet run -p .\benchmarks\MiniExcel.Benchmarks\ -c Release -f netcoreapp3.1 -- -f * --join
|
||||
```
|
||||
|
||||
最後一次運行規格、結果 :
|
||||
最後一次運行規格、結果 :
|
||||
|
||||
```bash
|
||||
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
|
||||
IterationCount=3 LaunchCount=3 WarmupCount=3
|
||||
```
|
||||
|
||||
Benchmark History : [Link](https://github.com/shps951023/MiniExcel/issues/276)
|
||||
@ -159,11 +159,11 @@ using (var stream = File.OpenRead(path))
|
||||
|
||||
var rows = MiniExcel.Query(path).ToList();
|
||||
|
||||
// or
|
||||
// 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);
|
||||
@ -173,9 +173,9 @@ using (var stream = File.OpenRead(path))
|
||||
|
||||
#### 3. 查詢資料以第一行數據當Key [[Try it]](https://dotnetfiddle.net/w5WD1J)
|
||||
|
||||
注意 : 同名以右邊數據為準
|
||||
注意 : 同名以右邊數據為準
|
||||
|
||||
Input Excel :
|
||||
Input Excel :
|
||||
|
||||
| Column1 | Column2 |
|
||||
| -------- | -------- |
|
||||
@ -217,7 +217,7 @@ using (var stream = File.OpenRead(path))
|
||||
}
|
||||
```
|
||||
|
||||
與其他框架效率比較 :
|
||||
與其他框架效率比較 :
|
||||
|
||||
![queryfirst](https://user-images.githubusercontent.com/12729184/111072392-6037a900-8515-11eb-9693-5ce2dad1e460.gif)
|
||||
|
||||
@ -255,8 +255,8 @@ foreach(IDictionary<string,object> row in MiniExcel.Query(path))
|
||||
//..
|
||||
}
|
||||
|
||||
// or
|
||||
var rows = MiniExcel.Query(path).Cast<IDictionary<string,object>>();
|
||||
// or
|
||||
var rows = MiniExcel.Query(path).Cast<IDictionary<string,object>>();
|
||||
```
|
||||
|
||||
|
||||
@ -281,15 +281,15 @@ MiniExcel.Query(path,useHeaderRow:true,startCell:"B3")
|
||||
|
||||
#### 11. 合併的單元格填充
|
||||
|
||||
注意 : 效率相對於`沒有使用合併填充`來說差
|
||||
注意 : 效率相對於`沒有使用合併填充`來說差
|
||||
底層原因 : OpenXml 標准將 mergeCells 放在文件最下方,導致需要遍歷兩次 sheetxml
|
||||
|
||||
```csharp
|
||||
var config = new OpenXmlConfiguration()
|
||||
{
|
||||
FsillMergedCells = true
|
||||
};
|
||||
var rows = MiniExcel.Query(path, configuration: config);
|
||||
var config = new OpenXmlConfiguration()
|
||||
{
|
||||
FsillMergedCells = true
|
||||
};
|
||||
var rows = MiniExcel.Query(path, configuration: config);
|
||||
```
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/117973630-3527d500-b35f-11eb-95c3-bde255f8114e.png)
|
||||
@ -326,7 +326,7 @@ MiniExcel.Query(path, configuration: config);
|
||||
1. 必須是非abstract 類別有公開無參數構造函數
|
||||
2. MiniExcel SaveAs 支援 `IEnumerable參數延遲查詢`,除非必要請不要使用 ToList 等方法讀取全部資料到記憶體
|
||||
|
||||
圖片 : 是否呼叫 ToList 的記憶體差別
|
||||
圖片 : 是否呼叫 ToList 的記憶體差別
|
||||
|
||||
#### ![image](https://user-images.githubusercontent.com/12729184/112587389-752b0b00-8e38-11eb-8a52-cfb76c57e5eb.png)
|
||||
|
||||
@ -355,7 +355,7 @@ var values = new List<Dictionary<string, object>>()
|
||||
MiniExcel.SaveAs(path, values);
|
||||
```
|
||||
|
||||
output :
|
||||
output :
|
||||
|
||||
| Column1 | Column2 |
|
||||
| --------- | ------- |
|
||||
@ -364,7 +364,7 @@ output :
|
||||
|
||||
|
||||
|
||||
#### 3. IDataReader
|
||||
#### 3. IDataReader
|
||||
|
||||
- 推薦使用,可以避免載入全部數據到記憶體
|
||||
|
||||
@ -514,7 +514,7 @@ MiniExcel.SaveAs(path, value,configuration:config);
|
||||
|
||||
#### 9. AutoFilter 篩選
|
||||
|
||||
從 0.19.0 支持,可藉由 OpenXmlConfiguration.AutoFilter 設定,預設為True。關閉 AutoFilter 方式 :
|
||||
從 0.19.0 支持,可藉由 OpenXmlConfiguration.AutoFilter 設定,預設為True。關閉 AutoFilter 方式 :
|
||||
|
||||
```csharp
|
||||
MiniExcel.SaveAs(path, value, configuration: new OpenXmlConfiguration() { AutoFilter = false });
|
||||
@ -551,7 +551,7 @@ MiniExcel.SaveAs(path, value);
|
||||
|
||||
```csharp
|
||||
var mergedFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
|
||||
|
||||
|
||||
var path = @"../../../../../samples/xlsx/TestMergeSameCells.xlsx";
|
||||
|
||||
MiniExcel.MergeSameCells(mergedFilePath, path);
|
||||
@ -559,7 +559,7 @@ MiniExcel.MergeSameCells(mergedFilePath, path);
|
||||
|
||||
```csharp
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
|
||||
var path = @"../../../../../samples/xlsx/TestMergeSameCells.xlsx";
|
||||
|
||||
memoryStream.MergeSameCells(path);
|
||||
@ -645,13 +645,13 @@ MiniExcel.SaveAs(@"C:\temp\Book1.xlsx", dt, configuration: configuration);
|
||||
|
||||
#### 1. 基本填充
|
||||
|
||||
模板:
|
||||
模板:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114537556-ed8d2b00-9c84-11eb-8303-a69f62c41e5b.png)
|
||||
|
||||
最終效果:
|
||||
最終效果:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114537490-d8180100-9c84-11eb-8c69-db58692f3a85.png)
|
||||
|
||||
代碼:
|
||||
代碼:
|
||||
```csharp
|
||||
// 1. By POCO
|
||||
var value = new
|
||||
@ -681,10 +681,10 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
> Note1: 同行從左往右以第一個 IEnumerableUse 當列表來源 (不支持同列多集合)
|
||||
|
||||
模板:
|
||||
模板:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114564652-14f2f080-9ca3-11eb-831f-09e3fedbc5fc.png)
|
||||
|
||||
最終效果:
|
||||
最終效果:
|
||||
![image](https://user-images.githubusercontent.com/12729184/114564204-b2015980-9ca2-11eb-900d-e21249f93f7c.png)
|
||||
|
||||
代碼:
|
||||
@ -725,15 +725,15 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
|
||||
> Note: 支持多 sheet 填充,並共用同一組參數
|
||||
|
||||
模板:
|
||||
模板:
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114565255-acf0da00-9ca3-11eb-8a7f-8131b2265ae8.png)
|
||||
|
||||
最終效果:
|
||||
最終效果:
|
||||
|
||||
![image](https://user-images.githubusercontent.com/12729184/114565329-bf6b1380-9ca3-11eb-85e3-3969e8bf6378.png)
|
||||
|
||||
代碼:
|
||||
代碼:
|
||||
|
||||
```csharp
|
||||
// 1. By POCO
|
||||
@ -955,7 +955,7 @@ public class ExcelAttributeDemo
|
||||
[ExcelIgnore]
|
||||
public string Test3 { get; set; }
|
||||
[ExcelColumnIndex("I")] // 系統會自動轉換"I"為第8列
|
||||
public string Test4 { get; set; }
|
||||
public string Test4 { get; set; }
|
||||
public string Test5 { get; } //系統會忽略此列
|
||||
public string Test6 { get; private set; } //set非公開,系統會忽略
|
||||
[ExcelColumnIndex(3)] // 從0開始索引
|
||||
@ -1047,7 +1047,7 @@ public class TestIssueI4TXGTDto
|
||||
}
|
||||
```
|
||||
|
||||
#### 6. ExcelColumnAttribute
|
||||
#### 6. ExcelColumnAttribute
|
||||
|
||||
從 1.26.0 版本開始,可以簡化多Attribute寫法
|
||||
```csharp
|
||||
@ -1060,13 +1060,13 @@ public class TestIssueI4TXGTDto
|
||||
}
|
||||
```
|
||||
|
||||
#### 7. DynamicColumnAttribute 動態設定 Column
|
||||
#### 7. DynamicColumnAttribute 動態設定 Column
|
||||
|
||||
從 1.26.0 版本開始,可以動態設定 Column 的屬性
|
||||
```csharp
|
||||
var config = new OpenXmlConfiguration
|
||||
{
|
||||
DynamicColumns = new DynamicExcelColumn[] {
|
||||
DynamicColumns = new DynamicExcelColumn[] {
|
||||
new DynamicExcelColumn("id"){Ignore=true},
|
||||
new DynamicExcelColumn("name"){Index=1,Width=10},
|
||||
new DynamicExcelColumn("createdate"){Index=0,Format="yyyy-MM-dd",Width=15},
|
||||
@ -1099,7 +1099,7 @@ v1.28.0 開始支持 CSV 插入新增,在最後一行新增N筆數據
|
||||
MiniExcel.SaveAs(path, value);
|
||||
}
|
||||
// 最後一行新增一行數據
|
||||
{
|
||||
{
|
||||
var value = new { ID=3,Name = "Mike", InDate = new DateTime(2021, 04, 23) };
|
||||
MiniExcel.Insert(path, value);
|
||||
}
|
||||
@ -1153,7 +1153,7 @@ stream.Query(excelType:ExcelType.XLSX);
|
||||
預設以 `,` 作為分隔符,自定義請修改 `Seperator` 屬性
|
||||
|
||||
```csharp
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
{
|
||||
Seperator=';'
|
||||
};
|
||||
@ -1167,7 +1167,7 @@ MiniExcel.SaveAs(path, values,configuration: config);
|
||||
預設以 `\r\n` 作為換行符,自定義請修改 `NewLine` 屬性
|
||||
|
||||
```csharp
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
var config = new MiniExcelLibs.Csv.CsvConfiguration()
|
||||
{
|
||||
NewLine='\n'
|
||||
};
|
||||
@ -1236,13 +1236,13 @@ MiniExcel.SaveAs(path, value,excelType:ExcelType.CSV, configuration: config);
|
||||
public static Task SaveAsAsync(string path, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.UNKNOWN, IConfiguration configuration = null)
|
||||
public static Task SaveAsAsync(this Stream stream, object value, bool printHeader = true, string sheetName = "Sheet1", ExcelType excelType = ExcelType.XLSX, IConfiguration configuration = null)
|
||||
public static Task<IEnumerable<dynamic>> QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<T>> QueryAsync<T>(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new()
|
||||
public static Task<IEnumerable<IDictionary<string, object>>> QueryAsync(this Stream stream, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, string templatePath, object value)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(this Stream stream, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, string templatePath, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value)
|
||||
public static Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value)
|
||||
public static Task<DataTable> QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
|
||||
```
|
||||
|
||||
@ -1265,7 +1265,7 @@ public class Dto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public I49RYZUserType UserType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type
|
||||
{
|
||||
@ -1289,11 +1289,16 @@ public enum Type
|
||||
```csharp
|
||||
MiniExcel.ConvertXlsxToCsv(xlsxPath, csvPath);
|
||||
MiniExcel.ConvertXlsxToCsv(xlsxStream, csvStream);
|
||||
MiniExcel.ConvertXlsxToCsv(csvPath, xlsxPath);
|
||||
MiniExcel.ConvertXlsxToCsv(csvStream, xlsxStream);
|
||||
MiniExcel.ConvertCsvToXlsx(csvPath, xlsxPath);
|
||||
MiniExcel.ConvertCsvToXlsx(csvStream, xlsxStream);
|
||||
```
|
||||
```csharp
|
||||
using (var excelStream = new FileStream(path: filePath, FileMode.Open, FileAccess.Read))
|
||||
using (var csvStream = new MemoryStream())
|
||||
{
|
||||
MiniExcel.ConvertXlsxToCsv(excelStream, csvStream);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 3. 自定義 CultureInfo
|
||||
|
||||
@ -1302,7 +1307,7 @@ MiniExcel.ConvertXlsxToCsv(csvStream, xlsxStream);
|
||||
```csharp
|
||||
var config = new CsvConfiguration()
|
||||
{
|
||||
Culture = new CultureInfo("fr-FR"),
|
||||
Culture = new CultureInfo("fr-FR"),
|
||||
};
|
||||
MiniExcel.SaveAs(path, value, configuration: config);
|
||||
|
||||
@ -1342,10 +1347,10 @@ using (var connection = new SQLiteConnection(connectionString))
|
||||
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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1478,19 +1483,19 @@ public class ApiController : Controller
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var rows = MiniExcel.Query(path);
|
||||
|
||||
Console.WriteLine("==== No.1 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:1));
|
||||
Console.WriteLine("==== No.50 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:50));
|
||||
Console.WriteLine("==== No.5000 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:5000));
|
||||
var rows = MiniExcel.Query(path);
|
||||
|
||||
Console.WriteLine("==== No.1 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:1));
|
||||
Console.WriteLine("==== No.50 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:50));
|
||||
Console.WriteLine("==== No.5000 Page ====");
|
||||
Console.WriteLine(Page(rows,pageSize:3,page:5000));
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Page<T>(IEnumerable<T> en, int pageSize, int page)
|
||||
{
|
||||
return en.Skip(page * pageSize).Take(pageSize);
|
||||
return en.Skip(page * pageSize).Take(pageSize);
|
||||
}
|
||||
```
|
||||
|
||||
@ -1523,70 +1528,70 @@ response.End();
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var value = new Order[] {
|
||||
new Order(){OrderNo = "SO01",CustomerID="C001",ProductID="P001",Qty=100,Amt=500},
|
||||
new Order(){OrderNo = "SO02",CustomerID="C002",ProductID="P002",Qty=300,Amt=400},
|
||||
};
|
||||
var value = new Order[] {
|
||||
new Order(){OrderNo = "SO01",CustomerID="C001",ProductID="P001",Qty=100,Amt=500},
|
||||
new Order(){OrderNo = "SO02",CustomerID="C002",ProductID="P002",Qty=300,Amt=400},
|
||||
};
|
||||
|
||||
Console.WriteLine("en-Us and Sales role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "en-US";
|
||||
var role = "Sales";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
Console.WriteLine("en-Us and Sales role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "en-US";
|
||||
var role = "Sales";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
|
||||
Console.WriteLine("zh-CN and PMC role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "zh-CN";
|
||||
var role = "PMC";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
Console.WriteLine("zh-CN and PMC role");
|
||||
{
|
||||
var path = Path.GetTempPath() + Guid.NewGuid() + ".xlsx";
|
||||
var lang = "zh-CN";
|
||||
var role = "PMC";
|
||||
MiniExcel.SaveAs(path, GetOrders(lang, role, value));
|
||||
MiniExcel.Query(path, true).Dump();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Dictionary<string, object>> GetOrders(string lang, string role, Order[] orders)
|
||||
{
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var newOrder = new Dictionary<string, object>();
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var newOrder = new Dictionary<string, object>();
|
||||
|
||||
if (lang == "zh-CN")
|
||||
{
|
||||
newOrder.Add("客戶編號", order.CustomerID);
|
||||
newOrder.Add("訂單編號", order.OrderNo);
|
||||
newOrder.Add("產品編號", order.ProductID);
|
||||
newOrder.Add("數量", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("價格", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else if (lang == "en-US")
|
||||
{
|
||||
newOrder.Add("Customer ID", order.CustomerID);
|
||||
newOrder.Add("Order No", order.OrderNo);
|
||||
newOrder.Add("Product ID", order.ProductID);
|
||||
newOrder.Add("Quantity", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("Amount", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException($"lang {lang} wrong");
|
||||
}
|
||||
}
|
||||
if (lang == "zh-CN")
|
||||
{
|
||||
newOrder.Add("客戶編號", order.CustomerID);
|
||||
newOrder.Add("訂單編號", order.OrderNo);
|
||||
newOrder.Add("產品編號", order.ProductID);
|
||||
newOrder.Add("數量", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("價格", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else if (lang == "en-US")
|
||||
{
|
||||
newOrder.Add("Customer ID", order.CustomerID);
|
||||
newOrder.Add("Order No", order.OrderNo);
|
||||
newOrder.Add("Product ID", order.ProductID);
|
||||
newOrder.Add("Quantity", order.Qty);
|
||||
if (role == "Sales")
|
||||
newOrder.Add("Amount", order.Amt);
|
||||
yield return newOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException($"lang {lang} wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Order
|
||||
{
|
||||
public string OrderNo { get; set; }
|
||||
public string CustomerID { get; set; }
|
||||
public decimal Qty { get; set; }
|
||||
public string ProductID { get; set; }
|
||||
public decimal Amt { get; set; }
|
||||
public string OrderNo { get; set; }
|
||||
public string CustomerID { get; set; }
|
||||
public decimal Qty { get; set; }
|
||||
public string ProductID { get; set; }
|
||||
public decimal Amt { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
@ -1637,33 +1642,33 @@ Query 預設索引為字串Key : A,B,C....,想要改為數字索引,請建
|
||||
```csharp
|
||||
void Main()
|
||||
{
|
||||
var path = @"D:\git\MiniExcel\samples\xlsx\TestTypeMapping.xlsx";
|
||||
var rows = MiniExcel.Query(path,true);
|
||||
foreach (var r in ConvertToIntIndexRows(rows))
|
||||
{
|
||||
Console.Write($"column 0 : {r[0]} ,column 1 : {r[1]}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
var path = @"D:\git\MiniExcel\samples\xlsx\TestTypeMapping.xlsx";
|
||||
var rows = MiniExcel.Query(path,true);
|
||||
foreach (var r in ConvertToIntIndexRows(rows))
|
||||
{
|
||||
Console.Write($"column 0 : {r[0]} ,column 1 : {r[1]}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Dictionary<int, object>> ConvertToIntIndexRows(IEnumerable<object> rows)
|
||||
{
|
||||
ICollection<string> keys = null;
|
||||
var isFirst = true;
|
||||
foreach (IDictionary<string,object> r in rows)
|
||||
{
|
||||
if(isFirst)
|
||||
{
|
||||
keys = r.Keys;
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
var dic = new Dictionary<int, object>();
|
||||
var index = 0;
|
||||
foreach (var key in keys)
|
||||
dic[index++] = r[key];
|
||||
yield return dic;
|
||||
}
|
||||
ICollection<string> keys = null;
|
||||
var isFirst = true;
|
||||
foreach (IDictionary<string,object> r in rows)
|
||||
{
|
||||
if(isFirst)
|
||||
{
|
||||
keys = r.Keys;
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
var dic = new Dictionary<int, object>();
|
||||
var index = 0;
|
||||
foreach (var key in keys)
|
||||
dic[index++] = r[key];
|
||||
yield return dic;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1690,12 +1695,12 @@ IEnumerable版本
|
||||
```csharp
|
||||
public static IEnumerable<dynamic> QueryWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
|
||||
{
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string,object> row in rows)
|
||||
{
|
||||
if(row.Keys.Any(key=>row[key]!=null))
|
||||
yield return row;
|
||||
}
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string,object> row in rows)
|
||||
{
|
||||
if(row.Keys.Any(key=>row[key]!=null))
|
||||
yield return row;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1706,43 +1711,43 @@ DataTable版本
|
||||
```csharp
|
||||
public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
|
||||
{
|
||||
if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/
|
||||
sheetName = stream.GetSheetNames().First();
|
||||
if (sheetName == null && excelType != ExcelType.CSV) /*Issue #279*/
|
||||
sheetName = stream.GetSheetNames().First();
|
||||
|
||||
var dt = new DataTable(sheetName);
|
||||
var first = true;
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string, object> row in rows)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
var dt = new DataTable(sheetName);
|
||||
var first = true;
|
||||
var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
|
||||
foreach (IDictionary<string, object> row in rows)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var column = new DataColumn(key, typeof(object)) { Caption = key };
|
||||
dt.Columns.Add(column);
|
||||
}
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var column = new DataColumn(key, typeof(object)) { Caption = key };
|
||||
dt.Columns.Add(column);
|
||||
}
|
||||
|
||||
dt.BeginLoadData();
|
||||
first = false;
|
||||
}
|
||||
dt.BeginLoadData();
|
||||
first = false;
|
||||
}
|
||||
|
||||
var newRow = dt.NewRow();
|
||||
var isNull=true;
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var _v = row[key];
|
||||
if(_v!=null)
|
||||
isNull = false;
|
||||
newRow[key] = _v;
|
||||
}
|
||||
|
||||
if(!isNull)
|
||||
dt.Rows.Add(newRow);
|
||||
}
|
||||
var newRow = dt.NewRow();
|
||||
var isNull=true;
|
||||
foreach (var key in row.Keys)
|
||||
{
|
||||
var _v = row[key];
|
||||
if(_v!=null)
|
||||
isNull = false;
|
||||
newRow[key] = _v;
|
||||
}
|
||||
|
||||
dt.EndLoadData();
|
||||
return dt;
|
||||
if(!isNull)
|
||||
dt.Rows.Add(newRow);
|
||||
}
|
||||
|
||||
dt.EndLoadData();
|
||||
return dt;
|
||||
}
|
||||
```
|
||||
|
||||
@ -1753,8 +1758,8 @@ public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useH
|
||||
請改以Stream自行管控Stream行為,如
|
||||
|
||||
```C#
|
||||
using (var stream = File.Create("Demo.xlsx"))
|
||||
MiniExcel.SaveAs(stream,value);
|
||||
using (var stream = File.Create("Demo.xlsx"))
|
||||
MiniExcel.SaveAs(stream,value);
|
||||
```
|
||||
|
||||
|
||||
@ -1762,7 +1767,7 @@ public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useH
|
||||
從V1.25.0版本開始,支持 overwriteFile 參數,方便調整是否要覆蓋已存在文件
|
||||
|
||||
```csharp
|
||||
MiniExcel.SaveAs(path, value, overwriteFile: true);
|
||||
MiniExcel.SaveAs(path, value, overwriteFile: true);
|
||||
```
|
||||
|
||||
|
||||
@ -1782,7 +1787,7 @@ public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useH
|
||||
|
||||
### 感謝名單
|
||||
|
||||
#### [Jetbrains](https://www.jetbrains.com/)
|
||||
#### [Jetbrains](https://www.jetbrains.com/)
|
||||
|
||||
![jetbrains-variant-2](https://user-images.githubusercontent.com/12729184/123997015-8456c180-da02-11eb-829a-aec476fe8e94.png)
|
||||
|
||||
@ -1793,6 +1798,6 @@ public static DataTable QueryAsDataTableWithoutEmptyRow(Stream stream, bool useH
|
||||
|
||||
|
||||
|
||||
### Contributors
|
||||
### Contributors
|
||||
|
||||
![](https://contrib.rocks/image?repo=shps951023/MiniExcel)
|
@ -33,6 +33,7 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true</De
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net461'">
|
||||
<Reference Include="System.IO.Compression" />
|
||||
@ -45,11 +46,12 @@ Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true</De
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="miniexcel.snk">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="icon.png" Pack="true" PackagePath="\" />
|
||||
<None Include="..\..\README.md" Link="README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||
|
Loading…
Reference in New Issue
Block a user