Web Analytics

MiniExcel

⭐ 3234 stars German by mini-software

NuGet Build-Status star GitHub-Sterne Version DeepWiki fragen


Dieses Projekt ist Teil der .NET Foundation und unterliegt deren Verhaltenskodex.


English | 简体中文 | 繁體中文 | 日本語 | 한국어 | हिन्दी | ไทย | Français | Deutsch | Español | Italiano | Русский | Português | Nederlands | Polski | العربية | فارسی | Türkçe | Tiếng Việt | Bahasa Indonesia


Ihre Sterne oder Spenden können MiniExcel verbessern


Einführung

MiniExcel ist ein einfaches und effizientes Excel-Verarbeitungstool für .NET, das speziell entwickelt wurde, um den Speicherverbrauch zu minimieren.

Derzeit müssen die meisten beliebten Frameworks alle Daten aus einem Excel-Dokument in den Speicher laden, um Operationen zu erleichtern, was jedoch zu Speicherverbrauchsproblemen führen kann. MiniExcels Ansatz ist anders: Die Daten werden zeilenweise im Streaming-Verfahren verarbeitet, wodurch der ursprüngliche Verbrauch von möglicherweise Hunderten von Megabyte auf nur wenige Megabyte reduziert wird und Speicherüberlauf-(OOM)-Probleme effektiv verhindert werden.

flowchart LR
    A1(["Excel analysis
process"]) --> A2{{"Unzipping
XLSX file"}} --> A3{{"Parsing
OpenXML"}} --> A4{{"Model
conversion"}} --> A5(["Output"])

B1(["Other Excel
Frameworks"]) --> B2{{"Memory"}} --> B3{{"Memory"}} --> B4{{"Workbooks &
Worksheets"}} --> B5(["All rows at
the same time"])

C1(["MiniExcel"]) --> C2{{"Stream"}} --> C3{{"Stream"}} --> C4{{"POCO or dynamic"}} --> C5(["Deferred execution
row by row"])

classDef analysis fill:#D0E8FF,stroke:#1E88E5,color:#0D47A1,font-weight:bold; classDef others fill:#FCE4EC,stroke:#EC407A,color:#880E4F,font-weight:bold; classDef miniexcel fill:#E8F5E9,stroke:#388E3C,color:#1B5E20,font-weight:bold;

class A1,A2,A3,A4,A5 analysis; class B1,B2,B3,B4,B5 others; class C1,C2,C3,C4,C5 miniexcel;

Funktionen

Version 2.0 Vorschau

Wir arbeiten an einer zukünftigen MiniExcel-Version mit einer neuen modularen und fokussierten API, separaten Nuget-Paketen für Core- und Csv-Funktionalitäten, vollständiger Unterstützung für asynchron gestreamte Abfragen über IAsyncEnumerable, und noch mehr, was bald verfügbar sein wird! Die Pakete werden als Vorabversionen verfügbar sein, also probieren Sie sie gerne aus und geben Sie uns Feedback!

Wenn Sie das tun, werfen Sie unbedingt auch einen Blick auf die neuen Dokumente und die Upgrade-Hinweise.

Schnellstart

Installation

Sie können das Paket von NuGet installieren

Versionshinweise

Bitte überprüfen Sie die Versionshinweise

TODO

Bitte überprüfen Sie TODO

Leistung

Der Code für die Benchmarks ist zu finden unter MiniExcel.Benchmarks.

Die zur Leistungsmessung verwendete Datei ist Test1,000,000x10.xlsx, ein 32MB großes Dokument mit 1.000.000 Zeilen * 10 Spalten, deren Zellen mit dem String "HelloWorld" gefüllt sind.

Um alle Benchmarks auszuführen, verwenden Sie:

dotnet run -project .\benchmarks\MiniExcel.Benchmarks -c Release -f net9.0 -filter * --join
Die Ergebnisse der Benchmarks für die neueste Version finden Sie hier.

Excel-Abfrage/Import

#### 1. Führen Sie eine Abfrage aus und ordnen Sie die Ergebnisse einem stark typisierten IEnumerable zu [[Ausprobieren]](https://dotnetfiddle.net/w5WD1J)

Es wird empfohlen, Stream.Query zu verwenden, da dies effizienter ist.

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

#### 2. Führen Sie eine Abfrage aus und ordnen Sie sie einer Liste von dynamischen Objekten zu, ohne head zu verwenden [[Ausprobieren]](https://dotnetfiddle.net/w5WD1J)

| MiniExcel | 1 | |-----------|---| | Github | 2 |


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); }

#### 3. Führen Sie eine Abfrage mit der ersten Kopfzeile aus [[Ausprobieren]](https://dotnetfiddle.net/w5WD1J)

Hinweis: Bei gleichem Spaltennamen wird die zuletzt rechts stehende verwendet

Eingabe-Excel:

| Spalte1 | Spalte2 | |-----------|---------| | MiniExcel | 1 | | Github | 2 |


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); }

#### 4. Abfrageunterstützung LINQ-Erweiterung First/Take/Skip ...usw.

Abfrage First

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); }

Leistung zwischen MiniExcel/ExcelDataReader/ClosedXML/EPPlus queryfirst

#### 5. Abfrage nach Blattname

MiniExcel.Query(path, sheetName: "SheetName");
//or
stream.Query(sheetName: "SheetName");
#### 6. Alle Blattnamen und Zeilen abfragen

var sheetNames = MiniExcel.GetSheetNames(path);
foreach (var sheetName in sheetNames)
{
    var rows = MiniExcel.Query(path, sheetName: sheetName);
}
#### 7. Spalten abrufen

var columns = MiniExcel.GetColumns(path); // e.g result : ["A","B"...]

var cnt = columns.Count; // get column count

#### 8. Dynamische Abfrage wirft Zeile zu IDictionary

foreach(IDictionary row in MiniExcel.Query(path))
{
    //..
}

// or var rows = MiniExcel.Query(path).Cast>(); // or Query specified ranges (capitalized) // A2 represents the second row of column A, C3 represents the third row of column C // If you don't want to restrict rows, just don't include numbers var rows = MiniExcel.QueryRange(path, startCell: "A2", endCell: "C3").Cast>();

#### 9. Excel-Abfrage gibt DataTable zurück

Nicht empfohlen, da DataTable alle Daten in den Speicher lädt und damit das Merkmal des geringen Speicherverbrauchs von MiniExcel verloren geht.

``C# var table = MiniExcel.QueryAsDataTable(path, useHeaderRow: true);

image

#### 10. Geben Sie die Zelle an, ab der die Daten gelesen werden sollen

csharp MiniExcel.Query(path,useHeaderRow:true,startCell:"B3")
image

#### 11. Zusammengeführte Zellen ausfüllen

Hinweis: Die Effizienz ist geringer im Vergleich zu ohne Verwendung der Zusammenführungsfüllung

Grund: Der OpenXml-Standard platziert mergeCells am Ende der Datei, was dazu führt, dass das sheetxml zweimal durchlaufen werden muss

csharp var config = new OpenXmlConfiguration() { FillMergedCells = true }; var rows = MiniExcel.Query(path, configuration: config);
image

unterstützt variablen Länge und Breite bei Mehrzeilen- und Mehrspaltenausfüllung

image

#### 12. Große Dateien mit festplattenbasiertem Cache lesen (Disk-Base Cache - SharedString)

Wenn die SharedStrings-Größe 5 MB überschreitet, verwendet MiniExcel standardmäßig einen lokalen Festplattencache, z. B. 10x100000.xlsx (eine Million Zeilendaten). Wenn der Festplattencache deaktiviert ist, liegt die maximale Speichernutzung bei 195MB, aber mit aktiviertem Festplattencache werden nur 65MB benötigt. Beachten Sie, dass diese Optimierung etwas Effizienz kostet, sodass sich in diesem Fall die Lesezeit von 7,4 Sekunden auf 27,2 Sekunden erhöht. Wenn Sie dies nicht benötigen, können Sie den Festplattencache mit folgendem Code deaktivieren:

csharp var config = new OpenXmlConfiguration { EnableSharedStringCache = false }; MiniExcel.Query(path,configuration: config)
Sie können SharedStringCacheSize verwenden, um die Größe der sharedString-Datei über die festgelegte Größe für das Festplatten-Caching hinaus zu ändern.
csharp var config = new OpenXmlConfiguration { SharedStringCacheSize=50010241024 }; MiniExcel.Query(path, configuration: config);
image

image

Erstellen/Exportieren von Excel

  • Muss ein nicht-abstrakter Typ mit einem öffentlichen parameterlosen Konstruktor sein.
  • MiniExcel unterstützt IEnumerable-Parameter mit verzögerter Ausführung. Wenn Sie möglichst wenig Speicher verwenden möchten, rufen Sie bitte keine Methoden wie ToList auf.
z.B.: ToList oder kein Speicherverbrauch image

#### 1. Anonym oder stark typisiert [[Ausprobieren]](https://dotnetfiddle.net/w5WD1J)

csharp var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx"); MiniExcel.SaveAs(path, new[] { new { Column1 = "MiniExcel", Column2 = 1 }, new { Column1 = "Github", Column2 = 2} });
#### 2. IEnumerable>

csharp var values = new List>() { new Dictionary{{ "Column1", "MiniExcel" }, { "Column2", 1 } }, new Dictionary{{ "Column1", "Github" }, { "Column2", 2 } } }; MiniExcel.SaveAs(path, values);
Dateiergebnis erstellen :

| Spalte1 | Spalte2 | |-----------|---------| | MiniExcel | 1 | | Github | 2 |

#### 3. IDataReader

  • Empfohlen, da es vermeidet, dass alle Daten in den Speicher geladen werden
csharp MiniExcel.SaveAs(path, reader);
image

DataReader exportiert mehrere Tabellenblätter (empfohlen von Dapper ExecuteReader)

csharp using (var cnn = Connection) { cnn.Open(); var sheets = new Dictionary(); sheets.Add("sheet1", cnn.ExecuteReader("select 1 id")); sheets.Add("sheet2", cnn.ExecuteReader("select 2 id")); MiniExcel.SaveAs("Demo.xlsx", sheets); }
#### 4. Datentabelle

  • Nicht empfohlen, da alle Daten in den Speicher geladen werden
  • DataTable verwendet zuerst die Beschriftung als Spaltennamen, dann den Spaltennamen
csharp 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);

####  5. Dapper-Abfrage

Danke @shaofing #552, bitte verwenden Sie CommandDefinition + CommandFlags.NoCache

csharp using (var connection = GetConnection(connectionString)) { var rows = connection.Query( new CommandDefinition( @"select 'MiniExcel' as Column1,1 as Column2 union all select 'Github',2" , flags: CommandFlags.NoCache) ); // Note: QueryAsync will throw close connection exception MiniExcel.SaveAs(path, rows); }
Der untenstehende Code lädt alle Daten in den Speicher

csharp 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); }
#### 6. SaveAs in MemoryStream  [[Ausprobieren]](https://dotnetfiddle.net/JOen0e)

csharp using (var stream = new MemoryStream()) //support FileStream,MemoryStream ect. { stream.SaveAs(values); }
z. B.: API zum Exportieren von Excel

csharp public IActionResult DownloadExcel() { var values = new[] { new { Column1 = "MiniExcel", Column2 = 1 }, new { Column1 = "Github", Column2 = 2} };

var memoryStream = new MemoryStream(); memoryStream.SaveAs(values); memoryStream.Seek(0, SeekOrigin.Begin); return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { FileDownloadName = "demo.xlsx" }; }

#### 7. Erstellen Sie mehrere Arbeitsblätter

csharp // 1. Dictionary var users = new[] { new { Name = "Jack", Age = 25 }, new { Name = "Mike", Age = 44 } }; var department = new[] { new { ID = "01", Name = "HR" }, new { ID = "02", Name = "IT" } }; var sheets = new Dictionary { ["users"] = users, ["department"] = department }; MiniExcel.SaveAs(path, sheets);

// 2. DataSet var sheets = new DataSet(); sheets.Add(UsersDataTable); sheets.Add(DepartmentDataTable); //.. MiniExcel.SaveAs(path, sheets);

image

#### 8. TableStyles Optionen

Standardstil

image

Ohne Stilkonfiguration

csharp var config = new OpenXmlConfiguration() { TableStyles = TableStyles.None }; MiniExcel.SaveAs(path, value,configuration:config);
image

#### 9. AutoFilter

Seit v0.19.0 kann OpenXmlConfiguration.AutoFilter den AutoFilter aktivieren/deaktivieren, der Standardwert ist true, und die Einstellung des AutoFilters erfolgt folgendermaßen:

csharp MiniExcel.SaveAs(path, value, configuration: new OpenXmlConfiguration() { AutoFilter = false });
#### 10. Bild erstellen

csharp var value = new[] { new { Name="github",Image=File.ReadAllBytes(PathHelper.GetFile("images/github_logo.png"))}, new { Name="google",Image=File.ReadAllBytes(PathHelper.GetFile("images/google_logo.png"))}, new { Name="microsoft",Image=File.ReadAllBytes(PathHelper.GetFile("images/microsoft_logo.png"))}, new { Name="reddit",Image=File.ReadAllBytes(PathHelper.GetFile("images/reddit_logo.png"))}, new { Name="statck_overflow",Image=File.ReadAllBytes(PathHelper.GetFile("images/statck_overflow_logo.png"))}, }; MiniExcel.SaveAs(path, value);
image

#### 11. Byte-Array-Dateiexport

Seit Version 1.22.0 wird bei Werttyp byte[] standardmäßig der Dateipfad in der Zelle gespeichert. Beim Import kann das System dies wieder in ein byte[] umwandeln. Wenn Sie dies nicht verwenden möchten, können Sie OpenXmlConfiguration.EnableConvertByteArray auf false setzen, um die Systemeffizienz zu verbessern.

image

Seit Version 1.22.0 wird bei Werttyp byte[] standardmäßig der Dateipfad in der Zelle gespeichert. Beim Import kann das System dies wieder in ein byte[] umwandeln. Wenn Sie dies nicht verwenden möchten, können Sie OpenXmlConfiguration.EnableConvertByteArray auf false setzen, um die Systemeffizienz zu verbessern.

image

#### 12. Gleiche Zellen vertikal zusammenführen

Diese Funktion wird nur im xlsx-Format unterstützt und verbindet Zellen vertikal zwischen den Tags @merge und @endmerge. Sie können @mergelimit verwenden, um die Grenzen der vertikalen Zellzusammenführung einzuschränken.

csharp var mergedFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");

var path = @"../../../../../samples/xlsx/TestMergeWithTag.xlsx";

MiniExcel.MergeSameCells(mergedFilePath, path);

csharp var memoryStream = new MemoryStream();

var path = @"../../../../../samples/xlsx/TestMergeWithTag.xlsx";

memoryStream.MergeSameCells(path);

Dateiinhalt vor und nach dem Zusammenführen:

Ohne Merge-Limit:

Screenshot 2023-08-07 at 11 59 24

Screenshot 2023-08-07 at 11 59 57

Mit Merge-Limit:

Screenshot 2023-08-08 at 18 21 00

Screenshot 2023-08-08 at 18 21 40

#### 13. Null-Werte überspringen

Neue explizite Option, leere Zellen für Null-Werte zu schreiben:

csharp DataTable dt = new DataTable();

/ ... /

DataRow dr = dt.NewRow();

dr["Name1"] = "Somebody once"; dr["Name2"] = null; dr["Name3"] = "told me.";

dt.Rows.Add(dr);

OpenXmlConfiguration configuration = new OpenXmlConfiguration() { EnableWriteNullValueCell = true // Default value. };

MiniExcel.SaveAs(@"C:\temp\Book1.xlsx", dt, configuration: configuration);

image

xml Somebody once told me.
Vorheriges Verhalten:

csharp / ... /

OpenXmlConfiguration configuration = new OpenXmlConfiguration() { EnableWriteNullValueCell = false // Default value is true. };

MiniExcel.SaveAs(@"C:\temp\Book1.xlsx", dt, configuration: configuration);


image
xml Somebody once told me.
Funktioniert für null- und DBNull-Werte.

#### 14. Fenster fixieren

csharp / ... /

OpenXmlConfiguration configuration = new OpenXmlConfiguration() { FreezeRowCount = 1, // default is 1 FreezeColumnCount = 2 // default is 0 };

MiniExcel.SaveAs(@"C:\temp\Book1.xlsx", dt, configuration: configuration);

image

Daten in Excel-Vorlage einfügen

  • Die Deklaration ist ähnlich wie bei Vue-Templates {{Variablenname}} oder dem Collection-Rendering {{Sammlungsname.Feldname}}
  • Collection-Rendering unterstützt IEnumerable/DataTable/DapperRow
#### 1. Einfaches Ausfüllen

Vorlage: image

Ergebnis: image

Code:

csharp // 1. By POCO var value = new { Name = "Jack", CreateDate = new DateTime(2021, 01, 01), VIP = true, Points = 123 }; MiniExcel.SaveAsByTemplate(path, templatePath, value);

// 2. By Dictionary var value = new Dictionary() { ["Name"] = "Jack", ["CreateDate"] = new DateTime(2021, 01, 01), ["VIP"] = true, ["Points"] = 123 }; MiniExcel.SaveAsByTemplate(path, templatePath, value);

#### 2. IEnumerable-Datenbefüllung

Hinweis1: Verwenden Sie das erste IEnumerable derselben Spalte als Grundlage für das Ausfüllen der Liste

Vorlage: image

Ergebnis: image

Code:

csharp //1. By POCO var value = new { employees = new[] { new {name="Jack",department="HR"}, new {name="Lisa",department="HR"}, new {name="John",department="HR"}, new {name="Mike",department="IT"}, new {name="Neo",department="IT"}, new {name="Loan",department="IT"} } }; MiniExcel.SaveAsByTemplate(path, templatePath, value);

//2. By Dictionary var value = new Dictionary() { ["employees"] = new[] { new {name="Jack",department="HR"}, new {name="Lisa",department="HR"}, new {name="John",department="HR"}, new {name="Mike",department="IT"}, new {name="Neo",department="IT"}, new {name="Loan",department="IT"} } }; MiniExcel.SaveAsByTemplate(path, templatePath, value);

#### 3. Komplexe Datenausfüllung

Hinweis: Unterstützt mehrere Tabellenblätter und die Verwendung derselben Variable

Vorlage:

image

Ergebnis:

image

csharp // 1. By POCO var value = new { title = "FooCompany", managers = new[] { new {name="Jack",department="HR"}, new {name="Loan",department="IT"} }, employees = new[] { new {name="Wade",department="HR"}, new {name="Felix",department="HR"}, new {name="Eric",department="IT"}, new {name="Keaton",department="IT"} } }; MiniExcel.SaveAsByTemplate(path, templatePath, value);

// 2. By Dictionary var value = new Dictionary() { ["title"] = "FooCompany", ["managers"] = new[] { new {name="Jack",department="HR"}, new {name="Loan",department="IT"} }, ["employees"] = new[] { new {name="Wade",department="HR"}, new {name="Felix",department="HR"}, new {name="Eric",department="IT"}, new {name="Keaton",department="IT"} } }; MiniExcel.SaveAsByTemplate(path, templatePath, value);

#### 4. Ausfüllen der Big Data-Leistung

HINWEIS: Die Verwendung von IEnumerable mit verzögerter Ausführung statt ToList kann den maximalen Speicherverbrauch in MiniExcel sparen

image

#### 5. Automatische Zuordnung des Zellwerttyps

Vorlage

image

Ergebnis

image

Klasse

csharp public class Poco { public string @string { get; set; } public int? @int { get; set; } public decimal? @decimal { get; set; } public double? @double { get; set; } public DateTime? datetime { get; set; } public bool? @bool { get; set; } public Guid? Guid { get; set; } }
Code
Code
Code
csharp var poco = new TestIEnumerableTypePoco { @string = "string", @int = 123, @decimal = decimal.Parse("123.45"), @double = (double)123.33, @datetime = new DateTime(2021, 4, 1), @bool = true, @Guid = Guid.NewGuid() }; var value = new { Ts = new[] { poco, new TestIEnumerableTypePoco{}, null, poco } }; MiniExcel.SaveAsByTemplate(path, templatePath, value);
#### 6. Beispiel: Github-Projekte auflisten

Vorlage

image

Ergebnis

image

Code

csharp var projects = new[] { new {Name = "MiniExcel",Link="https://github.com/mini-software/MiniExcel",Star=146, CreateTime=new DateTime(2021,03,01)}, new {Name = "HtmlTableHelper",Link="https://github.com/mini-software/HtmlTableHelper",Star=16, CreateTime=new DateTime(2020,02,01)}, new {Name = "PocoClassGenerator",Link="https://github.com/mini-software/PocoClassGenerator",Star=16, CreateTime=new DateTime(2019,03,17)} }; var value = new { User = "ITWeiHan", Projects = projects, TotalStar = projects.Sum(s => s.Star) }; MiniExcel.SaveAsByTemplate(path, templatePath, value);
#### 7. Gruppierte Datenausfüllung

csharp var value = new Dictionary() { ["employees"] = new[] { new {name="Jack",department="HR"}, new {name="Jack",department="HR"}, new {name="John",department="HR"}, new {name="John",department="IT"}, new {name="Neo",department="IT"}, new {name="Loan",department="IT"} } }; await MiniExcel.SaveAsByTemplateAsync(path, templatePath, value);
##### 1. Mit @group-Tag und mit @header-Tag

Vorher

before_with_header

Nachher

after_with_header

##### 2. Mit @group-Tag und ohne @header-Tag

Vorher

before_without_header

Nachher

after_without_header

##### 3. Ohne @group-Tag

Vorher

without_group

Nachher

without_group_after

#### 8. If/ElseIf/Else-Anweisungen innerhalb einer Zelle

Regeln:

  • Unterstützt DateTime, Double, Int mit den Operatoren ==, !=, >, >=, <, <=.
  • Unterstützt String mit den Operatoren ==, !=.
  • Jede Anweisung sollte in einer neuen Zeile stehen.
  • Vor und nach den Operatoren sollte ein einzelnes Leerzeichen stehen.
  • Es darf keinen Zeilenumbruch innerhalb der Anweisungen geben.
  • Die Zelle sollte genau wie unten formatiert sein.
csharp @if(name == Jack) {{employees.name}} @elseif(name == Neo) Test {{employees.name}} @else {{employees.department}} @endif
Vorher

if_before

Nachher

if_after

#### 9. DataTable als Parameter

csharp var managers = new DataTable(); { managers.Columns.Add("name"); managers.Columns.Add("department"); managers.Rows.Add("Jack", "HR"); managers.Rows.Add("Loan", "IT"); } var value = new Dictionary() { ["title"] = "FooCompany", ["managers"] = managers, }; MiniExcel.SaveAsByTemplate(path, templatePath, value);
#### 10. Formeln

##### 1. Beispiel Stellen Sie Ihrer Formel ein $ voran und verwenden Sie $enumrowstart und $enumrowend, um die Start- und Endzeilen des aufzählbaren Bereichs zu markieren:

image

Wenn die Vorlage gerendert wird, wird das $-Präfix entfernt und $enumrowstart sowie $enumrowend werden durch die Start- und Endzeilennummern des aufzählbaren Bereichs ersetzt:

image

##### 2. Weitere Beispiel-Formeln:

| | | |--------------|-------------------------------------------------------------------------------------------| | Summe | $=SUM(C{{$enumrowstart}}:C{{$enumrowend}}) | | Alt. Mittelw.| $=SUM(C{{$enumrowstart}}:C{{$enumrowend}}) / COUNT(C{{$enumrowstart}}:C{{$enumrowend}}) | | Bereich | $=MAX(C{{$enumrowstart}}:C{{$enumrowend}}) - MIN(C{{$enumrowstart}}:C{{$enumrowend}}) |

#### 11. Sonstiges

##### 1. Überprüfen des Template-Parameter-Schlüssels

Seit V1.24.0 wird ein fehlender Template-Parameter-Schlüssel standardmäßig ignoriert und durch einen leeren String ersetzt. Mit IgnoreTemplateParameterMissing kann gesteuert werden, ob eine Ausnahme ausgelöst wird oder nicht.

csharp var config = new OpenXmlConfiguration() { IgnoreTemplateParameterMissing = false, }; MiniExcel.SaveAsByTemplate(path, templatePath, value, config)
image

Excel Spaltenname/Index/Ignorieren-Attribut

#### 1. Spaltenname, Spaltenindex, Spalte ignorieren angeben

Excel-Beispiel

image

Code

csharp public class ExcelAttributeDemo { [ExcelColumnName("Column1")] public string Test1 { get; set; } [ExcelColumnName("Column2")] public string Test2 { get; set; } [ExcelIgnore] public string Test3 { get; set; } [ExcelColumnIndex("I")] // system will convert "I" to 8 index 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 public string Test7 { get; set; } }

var rows = MiniExcel.Query(path).ToList(); Assert.Equal("Column1", rows[0].Test1); Assert.Equal("Column2", rows[0].Test2); Assert.Null(rows[0].Test3); Assert.Equal("Test7", rows[0].Test4); Assert.Null(rows[0].Test5); Assert.Null(rows[0].Test6); Assert.Equal("Test4", rows[0].Test7);

#### 2. Benutzerdefiniertes Format (ExcelFormatAttribute)

Seit V0.21.0 wird eine Klasse unterstützt, die die Methode ToString(string content) enthält

Klasse

csharp public class Dto { public string Name { get; set; }

[ExcelFormat("MMMM dd, yyyy")] public DateTime InDate { get; set; } }

Code
Code
Code
csharp var value = new Dto[] { new Issue241Dto{ Name="Jack",InDate=new DateTime(2021,01,04)}, new Issue241Dto{ Name="Henry",InDate=new DateTime(2020,04,05)}, }; MiniExcel.SaveAs(path, value);
Ergebnis

image

Abfragen unterstützen benutzerdefinierte Formatkonvertierung

image

#### 3. Spaltenbreite festlegen (ExcelColumnWidthAttribute)

csharp public class Dto { [ExcelColumnWidth(20)] public int ID { get; set; } [ExcelColumnWidth(15.50)] public string Name { get; set; } }
#### 4. Mehrere Spaltennamen, die auf dieselbe Eigenschaft abgebildet werden.

csharp public class Dto { [ExcelColumnName(excelColumnName:"EmployeeNo",aliases:new[] { "EmpNo","No" })] public string Empno { get; set; } public string Name { get; set; } }
#### 5. System.ComponentModel.DisplayNameAttribute = ExcelColumnName.excelColumnNameAttribute

Seit Version 1.24.0 unterstützt das System System.ComponentModel.DisplayNameAttribute = ExcelColumnName.excelColumnNameAttribute

C# public class TestIssueI4TXGTDto { public int ID { get; set; } public string Name { get; set; } [DisplayName("Specification")] public string Spc { get; set; } [DisplayName("Unit Price")] public decimal Up { get; set; } }
#### 6. ExcelColumnAttribute

Seit Version V1.26.0 können mehrere Attribute wie folgt vereinfacht werden:

csharp public class TestIssueI4ZYUUDto { [ExcelColumn(Name = "ID",Index =0)] public string MyProperty { get; set; } [ExcelColumn(Name = "CreateDate", Index = 1,Format ="yyyy-MM",Width =100)] public DateTime MyProperty2 { get; set; } }
#### 7. DynamicColumnAttribute

Seit Version V1.26.0 können wir die Attribute von Column dynamisch festlegen

csharp var config = new OpenXmlConfiguration { 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}, new DynamicExcelColumn("point"){Index=2,Name="Account Point"}, } }; var path = PathHelper.GetTempPath(); var value = new[] { new { id = 1, name = "Jack", createdate = new DateTime(2022, 04, 12) ,point = 123.456} }; MiniExcel.SaveAs(path, value, configuration: config);
image

#### 8. DynamischesSheetAttribut

Seit V1.31.4 können wir die Attribute eines Sheets dynamisch festlegen. Wir können den Sheet-Namen und den Status (Sichtbarkeit) festlegen.

csharp var configuration = new OpenXmlConfiguration { DynamicSheets = new DynamicExcelSheet[] { new DynamicExcelSheet("usersSheet") { Name = "Users", State = SheetState.Visible }, new DynamicExcelSheet("departmentSheet") { Name = "Departments", State = SheetState.Hidden } } };

var users = new[] { new { Name = "Jack", Age = 25 }, new { Name = "Mike", Age = 44 } }; var department = new[] { new { ID = "01", Name = "HR" }, new { ID = "02", Name = "IT" } }; var sheets = new Dictionary { ["usersSheet"] = users, ["departmentSheet"] = department };

var path = PathHelper.GetTempPath(); MiniExcel.SaveAs(path, sheets, configuration: configuration);

Wir können auch das neue Attribut ExcelSheetAttribute verwenden:

C# [ExcelSheet(Name = "Departments", State = SheetState.Hidden)] private class DepartmentDto { [ExcelColumn(Name = "ID",Index = 0)] public string ID { get; set; } [ExcelColumn(Name = "Name",Index = 1)] public string Name { get; set; } }
### Hinzufügen, Löschen, Aktualisieren

#### Hinzufügen

v1.28.0 unterstützt das Einfügen von N Zeilen Daten im CSV nach der letzten Zeile

csharp // Origin { var value = new[] { new { ID=1,Name ="Jack",InDate=new DateTime(2021,01,03)}, new { ID=2,Name ="Henry",InDate=new DateTime(2020,05,03)}, }; 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); } // Insert N rows after last { var value = new[] { new { ID=4,Name ="Frank",InDate=new DateTime(2021,06,07)}, new { ID=5,Name ="Gloria",InDate=new DateTime(2022,05,03)}, }; MiniExcel.Insert(path, value); }
image

v1.37.0 unterstützt das Einfügen eines neuen Tabellenblatts in eine bestehende Arbeitsmappe in Excel

csharp // Origin excel { var value = new[] { new { ID=1,Name ="Jack",InDate=new DateTime(2021,01,03)}, new { ID=2,Name ="Henry",InDate=new DateTime(2020,05,03)}, }; MiniExcel.SaveAs(path, value, sheetName: "Sheet1"); } // Insert a new sheet { var value = new { ID=3,Name = "Mike", InDate = new DateTime(2021, 04, 23) }; MiniExcel.Insert(path, table, sheetName: "Sheet2"); }
#### Löschen (wartend)

#### Aktualisieren (wartend)

Excel-Typ Auto-Überprüfung

  • MiniExcel prüft standardmäßig anhand der Dateierweiterung, ob es sich um xlsx oder csv handelt, aber dies kann ungenau sein. Bitte geben Sie den Typ manuell an.
  • Bei Streams kann nicht erkannt werden, von welcher Excel-Datei sie stammen. Bitte geben Sie den Typ manuell an.
csharp stream.SaveAs(excelType:ExcelType.CSV); //or stream.SaveAs(excelType:ExcelType.XLSX); //or stream.Query(excelType:ExcelType.CSV); //or stream.Query(excelType:ExcelType.XLSX);

CSV

#### Hinweis

  • Standardmäßig wird der Typ string zurückgegeben, und der Wert wird nicht in Zahlen oder Datum/Uhrzeit umgewandelt, es sei denn, der Typ ist durch starke Generika-Typisierung definiert.
#### Benutzerdefiniertes Trennzeichen

Standardmäßig ist , das Trennzeichen, Sie können jedoch die Eigenschaft Seperator für die Anpassung ändern.

csharp var config = new MiniExcelLibs.Csv.CsvConfiguration() { Seperator=';' }; MiniExcel.SaveAs(path, values,configuration: config);
Seit V1.30.1 wird die Funktion zur Anpassung des Trennzeichens unterstützt (danke an @hyzx86)

csharp var config = new CsvConfiguration() { SplitFn = (row) => Regex.Split(row, $"\"" target="_blank" rel="noopener noreferrer">\t,$)") .Select(s => Regex.Replace(s.Replace("\"\"", "\""), "^\"|\"$", "")).ToArray() }; var rows = MiniExcel.Query(path, configuration: config).ToList();
#### Benutzerdefinierter Zeilenumbruch

Standardmäßig ist \r\n das Zeichen für den Zeilenumbruch, Sie können jedoch die Eigenschaft NewLine für Anpassungen ändern

csharp var config = new MiniExcelLibs.Csv.CsvConfiguration() { NewLine='\n' }; MiniExcel.SaveAs(path, values,configuration: config);
#### Benutzerdefinierte Codierung

  • Die Standardcodierung ist "Codierung aus Byte-Reihenfolgemarkierungen erkennen" (detectEncodingFromByteOrderMarks: true)
  • Wenn Sie benutzerdefinierte Codierungsanforderungen haben, passen Sie bitte die Eigenschaft StreamReaderFunc / StreamWriterFunc an
csharp // Read var config = new MiniExcelLibs.Csv.CsvConfiguration() { StreamReaderFunc = (stream) => new StreamReader(stream,Encoding.GetEncoding("gb2312")) }; var rows = MiniExcel.Query(path, true,excelType:ExcelType.CSV,configuration: config);

// Write var config = new MiniExcelLibs.Csv.CsvConfiguration() { StreamWriterFunc = (stream) => new StreamWriter(stream, Encoding.GetEncoding("gb2312")) }; MiniExcel.SaveAs(path, value,excelType:ExcelType.CSV, configuration: config);

#### Leere Zeichenfolgen als null lesen

Standardmäßig werden leere Werte als string.Empty zugeordnet. Sie können dieses Verhalten ändern

csharp var config = new MiniExcelLibs.Csv.CsvConfiguration() { ReadEmptyStringAsNull = true };
### DataReader

#### 1. GetReader Seit Version 1.23.0 können Sie GetDataReader verwenden

csharp using (var reader = MiniExcel.GetReader(path,true)) { while (reader.Read()) { for (int i = 0; i < reader.FieldCount; i++) { var value = reader.GetValue(i); } } }

Async

  • v0.17.0 unterstützt Async (Danke an isdaniel ( SHIH,BING-SIOU)](https://github.com/isdaniel))
csharp 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> QueryAsync(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) public static Task> QueryAsync(this Stream stream, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new() public static Task> QueryAsync(string path, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null) where T : class, new() public static Task>> 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(string path, string templatePath, object value) public static Task SaveAsByTemplateAsync(string path, byte[] templateBytes, object value) public static Task QueryAsDataTableAsync(string path, bool useHeaderRow = true, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
-  v1.25.0 unterstützt cancellationToken

Sonstiges

#### 1. Enum

Stellen Sie sicher, dass Excel- und Property-Name gleich sind, das System wird automatisch abgleichen (Groß-/Kleinschreibung wird ignoriert)

image

Seit V0.18.0 wird Enum Description unterstützt

csharp public class Dto { public string Name { get; set; } public I49RYZUserType UserType { get; set; } }

public enum Type { [Description("General User")] V1, [Description("General Administrator")] V2, [Description("Super Administrator")] V3 }

image

Seit Version 1.30.0 wird die Excel-Beschreibung zu Enum unterstützt, danke an @KaneLeung

#### 2. Konvertieren von CSV in XLSX oder Konvertieren von XLSX in CSV

csharp MiniExcel.ConvertXlsxToCsv(xlsxPath, csvPath); MiniExcel.ConvertXlsxToCsv(xlsxStream, csvStream); 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. Benutzerdefinierte CultureInfo

Seit Version 1.22.0 können Sie die CultureInfo wie unten gezeigt anpassen, standardmäßig verwendet das System CultureInfo.InvariantCulture.

var config = new CsvConfiguration()
{
    Culture = new CultureInfo("fr-FR"),
};
MiniExcel.SaveAs(path, value, configuration: config);

// or MiniExcel.Query(path, configuration: config);

#### 4. Benutzerdefinierte Puffergröße

    public abstract class Configuration : IConfiguration
    {
        public int BufferSize { get; set; } = 1024 * 512;
    }
#### 5. Schnellmodus

Das System steuert den Speicher nicht, aber Sie können eine schnellere Speicher-Geschwindigkeit erzielen.

var config = new OpenXmlConfiguration() { FastMode = true };
MiniExcel.SaveAs(path, reader,configuration:config);
#### 6. Batch-Bilder hinzufügen (MiniExcel.AddPicture)

Bitte fügen Sie Bilder hinzu, bevor Sie die Zeilendaten stapelweise generieren, da das System sonst beim Aufruf von AddPicture einen hohen Speicherverbrauch haben wird.

var images = new[]
{
    new MiniExcelPicture
    {
        ImageBytes = File.ReadAllBytes(PathHelper.GetFile("images/github_logo.png")),
        SheetName = null, // default null is first sheet
        CellAddress = "C3", // required
    },
    new MiniExcelPicture
    {
        ImageBytes = File.ReadAllBytes(PathHelper.GetFile("images/google_logo.png")),
        PictureType = "image/png", // default PictureType = image/png
        SheetName = "Demo",
        CellAddress = "C9", // required
        WidthPx = 100,
        HeightPx = 100,
    },
};
MiniExcel.AddPicture(path, images);
Bild

#### 7. Blattabmessungen abrufen

var dim = MiniExcel.GetSheetDimensions(path);

Beispiele:

#### 1. SQLite & Dapper Große Datei SQL-Insert vermeidet OOM

Hinweis: Bitte rufen Sie nach Query nicht die Methoden ToList/ToArray auf, da sonst alle Daten in den Speicher geladen werden.

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();
    }
}
Leistung: image

#### 2. ASP.NET Core 3.1 oder MVC 5 Download/Upload Excel Xlsx API Demo Ausprobieren

public class ApiController : Controller
{
    public IActionResult Index()
    {
        return new ContentResult
        {
            ContentType = "text/html",
            StatusCode = (int)HttpStatusCode.OK,
            Content = @"
DownloadExcel
DownloadExcelFromTemplatePath
DownloadExcelFromTemplateBytes

Upload Excel


public IActionResult DownloadExcel() { var values = new[] { new { Column1 = "MiniExcel", Column2 = 1 }, new { Column1 = "Github", Column2 = 2} }; var memoryStream = new MemoryStream(); memoryStream.SaveAs(values); memoryStream.Seek(0, SeekOrigin.Begin); return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { FileDownloadName = "demo.xlsx" }; }

public IActionResult DownloadExcelFromTemplatePath() { string templatePath = "TestTemplateComplex.xlsx";

Dictionary value = new Dictionary() { ["title"] = "FooCompany", ["managers"] = new[] { new {name="Jack",department="HR"}, new {name="Loan",department="IT"} }, ["employees"] = new[] { new {name="Wade",department="HR"}, new {name="Felix",department="HR"}, new {name="Eric",department="IT"}, new {name="Keaton",department="IT"} } };

MemoryStream memoryStream = new MemoryStream(); memoryStream.SaveAsByTemplate(templatePath, value); memoryStream.Seek(0, SeekOrigin.Begin); return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { FileDownloadName = "demo.xlsx" }; }

private static Dictionary TemplateBytesCache = new Dictionary();

static ApiController() { string templatePath = "TestTemplateComplex.xlsx"; byte[] bytes = System.IO.File.ReadAllBytes(templatePath); TemplateBytesCache.Add(templatePath, bytes); }

public IActionResult DownloadExcelFromTemplateBytes() { byte[] bytes = TemplateBytesCache["TestTemplateComplex.xlsx"];

Dictionary value = new Dictionary() { ["title"] = "FooCompany", ["managers"] = new[] { new {name="Jack",department="HR"}, new {name="Loan",department="IT"} }, ["employees"] = new[] { new {name="Wade",department="HR"}, new {name="Felix",department="HR"}, new {name="Eric",department="IT"}, new {name="Keaton",department="IT"} } };

MemoryStream memoryStream = new MemoryStream(); memoryStream.SaveAsByTemplate(bytes, value); memoryStream.Seek(0, SeekOrigin.Begin); return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { FileDownloadName = "demo.xlsx" }; }

public IActionResult UploadExcel(IFormFile excel) { var stream = new MemoryStream(); excel.CopyTo(stream);

foreach (var item in stream.Query(true)) { // do your logic etc. }

return Ok("File uploaded successfully"); } }

#### 3. Paginierungsabfrage

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)); }

public static IEnumerable Page(IEnumerable en, int pageSize, int page) { return en.Skip(page * pageSize).Take(pageSize); }

20210419

#### 4. WebForm exportiert Excel über MemoryStream

var fileName = "Demo.xlsx";
var sheetName = "Sheet1";
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
response.AddHeader("Content-Disposition", $"attachment;filename=\"{fileName}\"");
var values = new[] {
    new { Column1 = "MiniExcel", Column2 = 1 },
    new { Column1 = "Github", Column2 = 2}
};
var memoryStream = new MemoryStream();
memoryStream.SaveAs(values, sheetName: sheetName);
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(Response.OutputStream);
response.End();
#### 5. Dynamisches i18n-Mehrsprachigkeits- und Rollenberechtigungsmanagement

Erstellen Sie wie im Beispiel eine Methode zur Handhabung von i18n und Berechtigungsmanagement und verwenden Sie yield return, um IEnumerable> zurückzugeben, um dynamische und speichereffiziente Verarbeitungseffekte zu erzielen.

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},
    };

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(); } }

private IEnumerable> GetOrders(string lang, string role, Order[] orders) { foreach (var order in orders) { var newOrder = new Dictionary();

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; } }

image

FAQ

#### F: Excel-Header-Titel entspricht nicht dem Klasseneigenschaftsnamen, wie kann man zuordnen?

A. Bitte verwenden Sie das ExcelColumnName-Attribut

image

#### F: Wie kann man mehrere Arbeitsblätter abfragen oder exportieren?

A. Mit der Methode GetSheetNames und dem Parameter sheetName für die Abfrage.

var sheets = MiniExcel.GetSheetNames(path);
foreach (var sheet in sheets)
{
    Console.WriteLine($"sheet name : {sheet} ");
    var rows = MiniExcel.Query(path,useHeaderRow:true,sheetName:sheet);
    Console.WriteLine(rows);
}
image

#### F. Wie kann man Informationen über die Sichtbarkeit von Blättern abfragen oder exportieren?

A. Methode GetSheetInformations.

var sheets = MiniExcel.GetSheetInformations(path);
foreach (var sheetInfo in sheets)
{
    Console.WriteLine($"sheet index : {sheetInfo.Index} "); // next sheet index - numbered from 0
    Console.WriteLine($"sheet name : {sheetInfo.Name} ");   // sheet name
    Console.WriteLine($"sheet state : {sheetInfo.State} "); // sheet visibility state - visible / hidden
}
#### F. Lädt die Verwendung von Count alle Daten in den Speicher?

Nein, der Bildtest enthält 1 Million Zeilen * 10 Spalten Daten, die maximale Speichernutzung beträgt <60MB und es dauert 13,65 Sekunden

image

#### F. Wie verwendet Query ganzzahlige Indizes?

Der Standardindex von Query ist der Zeichenfolgen-Key: A,B,C.... Wenn Sie auf numerische Indizes umstellen möchten, erstellen Sie bitte die folgende Methode zur Umwandlung

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();
    }
}

private IEnumerable> ConvertToIntIndexRows(IEnumerable rows) { ICollection keys = null; var isFirst = true; foreach (IDictionary r in rows) { if(isFirst) { keys = r.Keys; isFirst = false; }

var dic = new Dictionary(); var index = 0; foreach (var key in keys) dic[index++] = r[key]; yield return dic; } } #### F. Kein Titel, leere Excel wird generiert, wenn der Wert beim Exportieren nach Excel leer ist

Da MiniExcel eine ähnliche Logik wie JSON.NET verwendet, um den Typ dynamisch aus den Werten zu bestimmen und die API-Bedienung zu vereinfachen, kann der Typ ohne Daten nicht ermittelt werden. Siehe Issue #133 für weitere Informationen.

image

Starker Typ & DataTable erzeugen Kopfzeilen, aber Dictionarys führen weiterhin zu leeren Excel-Dateien

#### F. Wie kann man die foreach-Schleife bei leerer Zeile stoppen?

MiniExcel kann mit LINQ TakeWhile verwendet werden, um den foreach-Iterator zu stoppen.

Image

#### F. Wie entfernt man leere Zeilen?

image

IEnumerable :

public static IEnumerable QueryWithoutEmptyRow(Stream stream, bool useHeaderRow, string sheetName, ExcelType excelType, string startCell, IConfiguration configuration)
{
    var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration);
    foreach (IDictionary row in rows)
    {
        if(row.Keys.Any(key=>row[key]!=null))
            yield return row;
    }
}

Datentabelle :

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();

var dt = new DataTable(sheetName); var first = true; var rows = stream.Query(useHeaderRow,sheetName,excelType,startCell,configuration); foreach (IDictionary row in rows) { if (first) {

foreach (var key in row.Keys) { var column = new DataColumn(key, typeof(object)) { Caption = key }; dt.Columns.Add(column); }

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); }

dt.EndLoadData(); return dt; }

#### F. Wie kann SaveAs(path,value) verwendet werden, um eine vorhandene Datei zu ersetzen, ohne den Fehler "Die Datei ...xlsx existiert bereits" auszulösen?

Bitte verwenden Sie die Stream-Klasse, um eine benutzerdefinierte Logik zum Erstellen von Dateien zu implementieren, z. B.:

`C# using (var stream = File.Create("Demo.xlsx")) MiniExcel.SaveAs(stream,value);

oder, seit V1.25.0, unterstützt SaveAs den Parameter overwriteFile, um das Überschreiben vorhandener Dateien zu aktivieren/deaktivieren

csharp MiniExcel.SaveAs(path, value, overwriteFile: true); ``

Einschränkungen und Hinweise

  • Unterstützt derzeit keine xls- und verschlüsselten Dateien
  • xlsm unterstützt nur Abfragen

Referenzen

ExcelDataReader / ClosedXML / Dapper / ExcelNumberFormat

Dank

#### Jetbrains

jetbrains-variant-2

Vielen Dank für die Bereitstellung einer kostenlosen All-Product-IDE für dieses Projekt (Lizenz)

Beitrag teilen & spenden

Link https://github.com/orgs/mini-software/discussions/754

Mitwirkende

--- Tranlated By Open Ai Tx | Last indexed: 2025-10-09 ---