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
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
- Minimiert den Speicherverbrauch, verhindert Out-of-Memory (OOM)-Fehler und vermeidet vollständige Garbage Collections
- Ermöglicht Echtzeit-Datenoperationen auf Zeilenebene für bessere Leistung bei großen Datensätzen
- Unterstützt LINQ mit verzögerter Ausführung, was schnelles und speichereffizientes Paging sowie komplexe Abfragen ermöglicht
- Leichtgewichtig, ohne die Notwendigkeit von Microsoft Office oder COM+-Komponenten, und eine DLL-Größe unter 500KB
- Einfacher und intuitiver API-Stil zum Lesen/Schreiben/Ausfüllen von Excel
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
- Excel importieren/abfragen
- Excel exportieren/erstellen
- Excel-Vorlage
- Excel Spaltenname/Index/Ignorieren-Attribut
- Beispiele
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();

#### 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)
- dynamischer Schlüssel ist
A.B.C.D..
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

#### 5. Abfrage nach Blattname
MiniExcel.Query(path, sheetName: "SheetName");
//or
stream.Query(sheetName: "SheetName");
#### 6. Alle Blattnamen und Zeilen abfragenvar sheetNames = MiniExcel.GetSheetNames(path);
foreach (var sheetName in sheetNames)
{
var rows = MiniExcel.Query(path, sheetName: sheetName);
}
#### 7. Spalten abrufenvar columns = MiniExcel.GetColumns(path); // e.g result : ["A","B"...]var cnt = columns.Count; // get column count
#### 8. Dynamische Abfrage wirft Zeile zu IDictionaryforeach(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ückNicht 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);

#### 10. Geben Sie die Zelle an, ab der die Daten gelesen werden sollen
csharp MiniExcel.Query(path,useHeaderRow:true,startCell:"B3")
csharp var config = new OpenXmlConfiguration() { FillMergedCells = true }; var rows = MiniExcel.Query(path, configuration: config);ohne Verwendung der Zusammenführungsfüllung#### 11. Zusammengeführte Zellen ausfüllen
Hinweis: Die Effizienz ist geringer im Vergleich zu
Grund: Der OpenXml-Standard platziert mergeCells am Ende der Datei, was dazu führt, dass das sheetxml zweimal durchlaufen werden muss

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

#### 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)
csharp var config = new OpenXmlConfiguration { SharedStringCacheSize=50010241024 }; MiniExcel.Query(path, configuration: config);Sie könnenSharedStringCacheSizeverwenden, um die Größe der sharedString-Datei über die festgelegte Größe für das Festplatten-Caching hinaus zu ändern.


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

#### 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}
});
csharp var values = new List#### 2.IEnumerable>
csharp MiniExcel.SaveAs(path, reader);Dateiergebnis erstellen :Empfohlen| Spalte1 | Spalte2 | |-----------|---------| | MiniExcel | 1 | | Github | 2 |
#### 3. IDataReader
, da es vermeidet, dass alle Daten in den Speicher geladen werden

DataReader exportiert mehrere Tabellenblätter (empfohlen von Dapper ExecuteReader)
csharp
using (var cnn = Connection)
{
cnn.Open();
var sheets = new Dictionarycsharp 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); }#### 4. DatentabelleNicht empfohlen, da alle Daten in den Speicher geladen werdenDataTable verwendet zuerst die Beschriftung als Spaltennamen, dann den Spaltennamen
MiniExcel.SaveAs(path, table);
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); }#### 5. Dapper-AbfrageCommandDefinition + CommandFlags.NoCacheDanke @shaofing #552, bitte verwenden Sie
Der untenstehende Code lädt alle Daten in den Speichercsharp
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 Excelcsharp
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// 2. DataSet var sheets = new DataSet(); sheets.Add(UsersDataTable); sheets.Add(DepartmentDataTable); //.. MiniExcel.SaveAs(path, sheets);

#### 8. TableStyles Optionen
Standardstil

Ohne Stilkonfiguration
csharp
var config = new OpenXmlConfiguration()
{
TableStyles = TableStyles.None
};
MiniExcel.SaveAs(path, value,configuration:config);
csharp MiniExcel.SaveAs(path, value, configuration: new OpenXmlConfiguration() { AutoFilter = false });OpenXmlConfiguration.AutoFilter#### 9. AutoFilter
Seit v0.19.0 kann
den AutoFilter aktivieren/deaktivieren, der Standardwert isttrue, und die Einstellung des AutoFilters erfolgt folgendermaßen:
#### 10. Bild erstellencsharp
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);
csharp var mergedFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");byte[]#### 11. Byte-Array-Dateiexport
Seit Version 1.22.0 wird bei Werttyp
standardmäßig der Dateipfad in der Zelle gespeichert. Beim Import kann das System dies wieder in einbyte[]umwandeln. Wenn Sie dies nicht verwenden möchten, können SieOpenXmlConfiguration.EnableConvertByteArrayauffalsesetzen, um die Systemeffizienz zu verbessern.byte[]
Seit Version 1.22.0 wird bei Werttyp
standardmäßig der Dateipfad in der Zelle gespeichert. Beim Import kann das System dies wieder in einbyte[]umwandeln. Wenn Sie dies nicht verwenden möchten, können SieOpenXmlConfiguration.EnableConvertByteArrayauffalsesetzen, um die Systemeffizienz zu verbessern.xlsx
#### 12. Gleiche Zellen vertikal zusammenführen
Diese Funktion wird nur im
-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.
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:


Mit Merge-Limit:


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

xml
Vorheriges Verhalten:csharp
/ ... /OpenXmlConfiguration configuration = new OpenXmlConfiguration() { EnableWriteNullValueCell = false // Default value is true. };
MiniExcel.SaveAs(@"C:\temp\Book1.xlsx", dt, configuration: configuration);
xml
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);
csharp // 1. By POCO var value = new { Name = "Jack", CreateDate = new DateTime(2021, 01, 01), VIP = true, Points = 123 }; MiniExcel.SaveAsByTemplate(path, templatePath, value);{{Variablenname}}Daten in Excel-Vorlage einfügen
- Die Deklaration ist ähnlich wie bei Vue-Templates
oder dem Collection-Rendering{{Sammlungsname.Feldname}}Collection-Rendering unterstützt IEnumerable/DataTable/DapperRow #### 1. Einfaches Ausfüllen
Vorlage:
Ergebnis:
Code:
// 2. By Dictionary
var value = new Dictionary#### 2. IEnumerable-Datenbefüllung
Hinweis1: Verwenden Sie das erste IEnumerable derselben Spalte als Grundlage für das Ausfüllen der Liste
Vorlage:

Ergebnis:

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#### 3. Komplexe Datenausfüllung
Hinweis: Unterstützt mehrere Tabellenblätter und die Verwendung derselben Variable
Vorlage:

Ergebnis:

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#### 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

#### 5. Automatische Zuordnung des Zellwerttyps
Vorlage

Ergebnis

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
Codecsharp
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 auflistenVorlage

Ergebnis

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üllungcsharp
var value = new Dictionarycsharp @if(name == Jack) {{employees.name}} @elseif(name == Neo) Test {{employees.name}} @else {{employees.department}} @endif##### 1. Mit@group-Tag und mit@header-TagVorher
Nachher
##### 2. Mit @group-Tag und ohne @header-Tag
Vorher
Nachher
##### 3. Ohne @group-Tag
Vorher
Nachher
#### 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.
Vorher
Nachher

#### 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 Dictionarycsharp var config = new OpenXmlConfiguration() { IgnoreTemplateParameterMissing = false, }; MiniExcel.SaveAsByTemplate(path, templatePath, value, config)#### 10. Formeln$##### 1. Beispiel Stellen Sie Ihrer Formel ein
voran und verwenden Sie$enumrowstartund$enumrowend, um die Start- und Endzeilen des aufzählbaren Bereichs zu markieren:$
Wenn die Vorlage gerendert wird, wird das
-Präfix entfernt und$enumrowstartsowie$enumrowendwerden durch die Start- und Endzeilennummern des aufzählbaren Bereichs ersetzt:$=SUM(C{{$enumrowstart}}:C{{$enumrowend}})
##### 2. Weitere Beispiel-Formeln:
| | | |--------------|-------------------------------------------------------------------------------------------| | Summe |
| | Alt. Mittelw.|$=SUM(C{{$enumrowstart}}:C{{$enumrowend}}) / COUNT(C{{$enumrowstart}}:C{{$enumrowend}})| | Bereich |$=MAX(C{{$enumrowstart}}:C{{$enumrowend}}) - MIN(C{{$enumrowstart}}:C{{$enumrowend}})|IgnoreTemplateParameterMissing#### 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
kann gesteuert werden, ob eine Ausnahme ausgelöst wird oder nicht.

Excel Spaltenname/Index/Ignorieren-Attribut
#### 1. Spaltenname, Spaltenindex, Spalte ignorieren angeben
Excel-Beispiel

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
#### 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
Codecsharp
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
Abfragen unterstützen benutzerdefinierte Formatkonvertierung

#### 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.excelColumnNameAttributeSeit 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. ExcelColumnAttributeSeit 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. DynamicColumnAttributeSeit 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);

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

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");
}
csharp stream.SaveAs(excelType:ExcelType.CSV); //or stream.SaveAs(excelType:ExcelType.XLSX); //or stream.Query(excelType:ExcelType.CSV); //or stream.Query(excelType:ExcelType.XLSX);#### Löschen (wartend)Dateierweiterung#### Aktualisieren (wartend)
Excel-Typ Auto-Überprüfung
- MiniExcel prüft standardmäßig anhand der
, 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 var config = new MiniExcelLibs.Csv.CsvConfiguration() { Seperator=';' }; MiniExcel.SaveAs(path, values,configuration: config);stringCSV
#### Hinweis
- Standardmäßig wird der Typ
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 EigenschaftSeperatorfür die Anpassung ändern.
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();
csharp var config = new MiniExcelLibs.Csv.CsvConfiguration() { NewLine='\n' }; MiniExcel.SaveAs(path, values,configuration: config);#### Benutzerdefinierter Zeilenumbruch\r\nStandardmäßig ist
das Zeichen für den Zeilenumbruch, Sie können jedoch die EigenschaftNewLinefür Anpassungen ändern
#### 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 lesenStandardmäß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 Taskcsharp public class Dto { public string Name { get; set; } public I49RYZUserType UserType { get; set; } }- v1.25.0 unterstütztcancellationToken。Sonstiges
#### 1. Enum
Stellen Sie sicher, dass Excel- und Property-Name gleich sind, das System wird automatisch abgleichen (Groß-/Kleinschreibung wird ignoriert)
Seit V0.18.0 wird Enum Description unterstützt
public enum Type { [Description("General User")] V1, [Description("General Administrator")] V2, [Description("Super Administrator")] V3 }

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);
#### 3. Benutzerdefinierte CultureInfo`csharp using (var excelStream = new FileStream(path: filePath, FileMode.Open, FileAccess.Read)) using (var csvStream = new MemoryStream()) { MiniExcel.ConvertXlsxToCsv(excelStream, csvStream); }
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. SchnellmodusDas 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);
#### 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:

#### 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. Paginierungsabfragevoid 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);
}

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

FAQ
#### F: Excel-Header-Titel entspricht nicht dem Klasseneigenschaftsnamen, wie kann man zuordnen?
A. Bitte verwenden Sie das ExcelColumnName-Attribut

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

#### 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

#### 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
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 istDa 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.

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.

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

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

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/754Mitwirkende
--- Tranlated By Open Ai Tx | Last indexed: 2025-10-09 ---










