11using MiniExcelLibs . OpenXml . Constants ;
2+ using MiniExcelLibs . OpenXml . Models ;
3+ using MiniExcelLibs . OpenXml . Styles ;
24using MiniExcelLibs . Utils ;
35using MiniExcelLibs . Zip ;
46using System ;
@@ -15,7 +17,7 @@ namespace MiniExcelLibs.OpenXml
1517{
1618 internal partial class ExcelOpenXmlSheetWriter : IExcelWriter
1719 {
18- public async Task SaveAsAsync ( CancellationToken cancellationToken = default ( CancellationToken ) )
20+ public async Task SaveAsAsync ( CancellationToken cancellationToken = default )
1921 {
2022 await GenerateDefaultOpenXmlAsync ( cancellationToken ) ;
2123
@@ -32,6 +34,67 @@ internal partial class ExcelOpenXmlSheetWriter : IExcelWriter
3234 _archive . Dispose ( ) ;
3335 }
3436
37+ public async Task InsertAsync ( bool overwriteSheet = false , CancellationToken cancellationToken = default )
38+ {
39+ if ( ! _configuration . FastMode )
40+ {
41+ throw new InvalidOperationException ( "Insert requires fast mode to be enabled" ) ;
42+ }
43+
44+ var sheetRecords = new ExcelOpenXmlSheetReader ( _stream , _configuration ) . GetWorkbookRels ( _archive . Entries ) . ToArray ( ) ;
45+ foreach ( var sheetRecord in sheetRecords . OrderBy ( o => o . Id ) )
46+ {
47+ _sheets . Add ( new SheetDto { Name = sheetRecord . Name , SheetIdx = ( int ) sheetRecord . Id , State = sheetRecord . State } ) ;
48+ }
49+ var existSheetDto = _sheets . SingleOrDefault ( s => s . Name == _defaultSheetName ) ;
50+ if ( existSheetDto != null && ! overwriteSheet )
51+ {
52+ throw new Exception ( $ "Sheet “{ _defaultSheetName } ” already exist") ;
53+ }
54+
55+ await GenerateStylesXmlAsync ( cancellationToken ) ; //GenerateStylesXml必须在校验overwriteSheet之后,避免不必要的样式更改
56+
57+ if ( existSheetDto == null )
58+ {
59+ currentSheetIndex = ( int ) sheetRecords . Max ( m => m . Id ) + 1 ;
60+ var insertSheetInfo = GetSheetInfos ( _defaultSheetName ) ;
61+ var insertSheetDto = insertSheetInfo . ToDto ( currentSheetIndex ) ;
62+ _sheets . Add ( insertSheetDto ) ;
63+ await CreateSheetXmlAsync ( _value , insertSheetDto . Path , cancellationToken ) ;
64+ }
65+ else
66+ {
67+ currentSheetIndex = existSheetDto . SheetIdx ;
68+ _archive . Entries . Single ( s => s . FullName == existSheetDto . Path ) . Delete ( ) ;
69+ _archive . Entries . SingleOrDefault ( s => s . FullName == ExcelFileNames . DrawingRels ( currentSheetIndex ) ) ? . Delete ( ) ;
70+ _archive . Entries . SingleOrDefault ( s => s . FullName == ExcelFileNames . Drawing ( currentSheetIndex ) ) ? . Delete ( ) ;
71+ await CreateSheetXmlAsync ( _value , existSheetDto . Path , cancellationToken ) ;
72+ }
73+
74+ await AddFilesToZipAsync ( cancellationToken ) ;
75+
76+ await GenerateDrawinRelXmlAsync ( currentSheetIndex , cancellationToken ) ;
77+
78+ await GenerateDrawingXmlAsync ( currentSheetIndex , cancellationToken ) ;
79+
80+ GenerateWorkBookXmls ( out StringBuilder workbookXml , out StringBuilder workbookRelsXml , out Dictionary < int , string > sheetsRelsXml ) ;
81+
82+ foreach ( var sheetRelsXml in sheetsRelsXml )
83+ {
84+ var sheetRelsXmlPath = ExcelFileNames . SheetRels ( sheetRelsXml . Key ) ;
85+ _archive . Entries . SingleOrDefault ( s => s . FullName == sheetRelsXmlPath ) ? . Delete ( ) ;
86+ await CreateZipEntryAsync ( sheetRelsXmlPath , null , ExcelXml . DefaultSheetRelXml . Replace ( "{{format}}" , sheetRelsXml . Value ) , cancellationToken ) ;
87+ }
88+
89+ _archive . Entries . SingleOrDefault ( s => s . FullName == ExcelFileNames . Workbook ) ? . Delete ( ) ;
90+ await CreateZipEntryAsync ( ExcelFileNames . Workbook , ExcelContentTypes . Workbook , ExcelXml . DefaultWorkbookXml . Replace ( "{{sheets}}" , workbookXml . ToString ( ) ) , cancellationToken ) ;
91+
92+ _archive . Entries . SingleOrDefault ( s => s . FullName == ExcelFileNames . WorkbookRels ) ? . Delete ( ) ;
93+ await CreateZipEntryAsync ( ExcelFileNames . WorkbookRels , null , ExcelXml . DefaultWorkbookXmlRels . Replace ( "{{sheets}}" , workbookRelsXml . ToString ( ) ) , cancellationToken ) ;
94+
95+ _archive . Dispose ( ) ;
96+ }
97+
3598 internal async Task GenerateDefaultOpenXmlAsync ( CancellationToken cancellationToken )
3699 {
37100 await CreateZipEntryAsync ( ExcelFileNames . Rels , ExcelContentTypes . Relationships , ExcelXml . DefaultRels , cancellationToken ) ;
@@ -589,7 +652,7 @@ private async Task WriteColumnsWidthsAsync(MiniExcelAsyncStreamWriter writer, IE
589652 await writer. WriteAsync( WorksheetXml. EndCols) ;
590653 }
591654
592- private static async Task PrintHeaderAsync( MiniExcelAsyncStreamWriter writer, List< ExcelColumnInfo> props)
655+ private async Task PrintHeaderAsync( MiniExcelAsyncStreamWriter writer, List< ExcelColumnInfo> props)
593656 {
594657 var xIndex = 1 ;
595658 var yIndex = 1 ;
@@ -658,9 +721,9 @@ private async Task<int> GenerateSheetByColumnInfoAsync<T>(MiniExcelAsyncStreamWr
658721 return yIndex - 1 ;
659722 }
660723
661- private static async Task WriteCellAsync( MiniExcelAsyncStreamWriter writer, string cellReference, string columnName)
724+ private async Task WriteCellAsync( MiniExcelAsyncStreamWriter writer, string cellReference, string columnName)
662725 {
663- await writer. WriteAsync( WorksheetXml. Cell( cellReference, "str", "1 ", ExcelOpenXmlUtils. EncodeXML( columnName) ) ) ;
726+ await writer. WriteAsync( WorksheetXml. Cell( cellReference, "str", GetCellXfId ( "1 ") , ExcelOpenXmlUtils. EncodeXML( columnName) ) ) ;
664727 }
665728
666729 private async Task WriteCellAsync( MiniExcelAsyncStreamWriter writer, int rowIndex, int cellIndex, object value, ExcelColumnInfo p, ExcelWidthCollection widthCollection)
@@ -670,7 +733,7 @@ private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowInde
670733
671734 if ( _configuration. EnableWriteNullValueCell && valueIsNull)
672735 {
673- await writer. WriteAsync( WorksheetXml. EmptyCell( columnReference, "2 ") ) ;
736+ await writer. WriteAsync( WorksheetXml. EmptyCell( columnReference, GetCellXfId ( "2 ") ) ) ;
674737 return ;
675738 }
676739
@@ -697,7 +760,7 @@ private async Task WriteCellAsync(MiniExcelAsyncStreamWriter writer, int rowInde
697760 }
698761 }
699762
700- await writer. WriteAsync( WorksheetXml. Cell( columnReference, dataType, styleIndex, cellValue, preserveSpace: preserveSpace, columnType: columnType) ) ;
763+ await writer. WriteAsync( WorksheetXml. Cell( columnReference, dataType, GetCellXfId ( styleIndex) , cellValue, preserveSpace: preserveSpace, columnType: columnType) ) ;
701764 widthCollection? . AdjustWidth( cellIndex, cellValue) ;
702765 }
703766
@@ -727,41 +790,59 @@ private async Task AddFilesToZipAsync(CancellationToken cancellationToken)
727790 /// </summary>
728791 private async Task GenerateStylesXmlAsync( CancellationToken cancellationToken)
729792 {
730- var styleXml = GetStylesXml( _configuration. DynamicColumns) ;
731-
732- await CreateZipEntryAsync(
733- ExcelFileNames. Styles,
734- ExcelContentTypes. Styles,
735- styleXml,
736- cancellationToken) ;
793+ using ( var context = new SheetStyleBuildContext( _zipDictionary, _archive, _utf8WithBom, _configuration. DynamicColumns) )
794+ {
795+ var builder = ( ISheetStyleBuilder) null ;
796+ switch ( _configuration. TableStyles)
797+ {
798+ case TableStyles. None:
799+ builder = new MinimalSheetStyleBuilder( context) ;
800+ break ;
801+ case TableStyles. Default:
802+ builder = new DefaultSheetStyleBuilder( context) ;
803+ break ;
804+ }
805+ var result = await builder. BuildAsync( cancellationToken) ;
806+ cellXfIdMap = result. CellXfIdMap;
807+ }
737808 }
738809
739810 private async Task GenerateDrawinRelXmlAsync( CancellationToken cancellationToken)
740811 {
741812 for ( int sheetIndex = 0 ; sheetIndex < _sheets. Count; sheetIndex++ )
742813 {
743- var drawing = GetDrawingRelationshipXml( sheetIndex) ;
744- await CreateZipEntryAsync(
745- ExcelFileNames. DrawingRels( sheetIndex) ,
746- string . Empty,
747- ExcelXml. DefaultDrawingXmlRels. Replace( "{ { format} } ", drawing) ,
748- cancellationToken) ;
814+ await GenerateDrawinRelXmlAsync( sheetIndex, cancellationToken) ;
749815 }
750816 }
751817
818+ private async Task GenerateDrawinRelXmlAsync( int sheetIndex, CancellationToken cancellationToken)
819+ {
820+ var drawing = GetDrawingRelationshipXml( sheetIndex) ;
821+ await CreateZipEntryAsync(
822+ ExcelFileNames. DrawingRels( sheetIndex) ,
823+ string . Empty,
824+ ExcelXml. DefaultDrawingXmlRels. Replace( "{ { format} } ", drawing) ,
825+ cancellationToken) ;
826+ }
827+
752828 private async Task GenerateDrawingXmlAsync( CancellationToken cancellationToken)
753829 {
754830 for ( int sheetIndex = 0 ; sheetIndex < _sheets. Count; sheetIndex++ )
755831 {
756- var drawing = GetDrawingXml( sheetIndex) ;
757- await CreateZipEntryAsync(
758- ExcelFileNames. Drawing( sheetIndex) ,
759- ExcelContentTypes. Drawing,
760- ExcelXml. DefaultDrawing. Replace( "{ { format} } ", drawing) ,
761- cancellationToken) ;
832+ await GenerateDrawingXmlAsync( sheetIndex, cancellationToken) ;
762833 }
763834 }
764835
836+ private async Task GenerateDrawingXmlAsync( int sheetIndex, CancellationToken cancellationToken)
837+ {
838+ var drawing = GetDrawingXml( sheetIndex) ;
839+ await CreateZipEntryAsync(
840+ ExcelFileNames. Drawing( sheetIndex) ,
841+ ExcelContentTypes. Drawing,
842+ ExcelXml. DefaultDrawing. Replace( "{ { format} } ", drawing) ,
843+ cancellationToken) ;
844+ }
845+
765846 /// <summary>
766847 /// workbook.xml 、 workbookRelsXml
767848 /// </summary>
0 commit comments