11using MiniExcelLibs . Utils ;
2+ using MiniExcelLibs . WriteAdapter ;
23using System ;
3- using System . Collections ;
44using System . Collections . Generic ;
5- using System . Data ;
65using System . Globalization ;
76using System . IO ;
87using System . Linq ;
8+ using System . Text ;
99using System . Threading ;
1010using System . Threading . Tasks ;
1111
@@ -31,205 +31,152 @@ public CsvWriter(Stream stream, object value, IConfiguration configuration, bool
3131
3232 public void SaveAs ( )
3333 {
34- var seperator = _configuration . Seperator . ToString ( ) ;
35- var newLine = _configuration . NewLine ;
34+ if ( _value == null )
3635 {
37- if ( _value == null )
38- {
39- _writer . Write ( "" ) ;
40- this . _writer . Flush ( ) ;
41- return ;
42- }
43-
44- var type = _value . GetType ( ) ;
45-
46- if ( _value is IDataReader dataReader )
47- {
48- GenerateSheetByIDataReader ( dataReader , seperator , newLine , _writer ) ;
49- }
50- else if ( _value is IEnumerable enumerable )
51- {
52- GenerateSheetByIEnumerable ( enumerable , seperator , newLine , _writer ) ;
53- }
54- else if ( _value is DataTable dataTable )
55- {
56- GenerateSheetByDataTable ( _writer , dataTable , seperator , newLine ) ;
57- }
58- else
59- {
60- throw new NotImplementedException ( $ "Type { type ? . Name } not Implemented. please issue for me.") ;
61- }
62-
63- this . _writer . Flush ( ) ;
36+ _writer . Write ( "" ) ;
37+ _writer . Flush ( ) ;
38+ return ;
6439 }
65- }
6640
67- public async Task SaveAsAsync ( CancellationToken cancellationToken = default )
68- {
69- await Task . Run ( ( ) => SaveAs ( ) , cancellationToken ) . ConfigureAwait ( false ) ;
41+ WriteValues ( _writer , _value ) ;
42+ _writer . Flush ( ) ;
7043 }
7144
7245 public void Insert ( bool overwriteSheet = false )
7346 {
7447 SaveAs ( ) ;
7548 }
7649
77- public async Task InsertAsync ( bool overwriteSheet = false , CancellationToken cancellationToken = default )
50+ private void AppendColumn ( StringBuilder rowBuilder , CellWriteInfo column )
7851 {
79- await Task . Run ( ( ) => SaveAs ( ) , cancellationToken ) . ConfigureAwait ( false ) ;
52+ rowBuilder . Append ( CsvHelpers . ConvertToCsvValue ( ToCsvString ( column . Value , column . Prop ) , _configuration . AlwaysQuote , _configuration . Seperator ) ) ;
53+ rowBuilder . Append ( _configuration . Seperator ) ;
8054 }
8155
82- private void GenerateSheetByIEnumerable ( IEnumerable values , string seperator , string newLine , StreamWriter writer )
56+ private void RemoveTrailingSeparator ( StringBuilder rowBuilder )
8357 {
84- Type genericType = null ;
85- List < ExcelColumnInfo > props = null ;
86- string mode = null ;
87-
88- var enumerator = values . GetEnumerator ( ) ;
89- var empty = ! enumerator . MoveNext ( ) ;
90- if ( empty )
91- {
92- // only when empty IEnumerable need to check this issue #133 https://github.com/shps951023/MiniExcel/issues/133
93- genericType = TypeHelper . GetGenericIEnumerables ( values ) . FirstOrDefault ( ) ;
94- if ( genericType == null || genericType == typeof ( object ) // sometime generic type will be object, e.g: https://user-images.githubusercontent.com/12729184/132812859-52984314-44d1-4ee8-9487-2d1da159f1f0.png
95- || typeof ( IDictionary < string , object > ) . IsAssignableFrom ( genericType )
96- || typeof ( IDictionary ) . IsAssignableFrom ( genericType )
97- || typeof ( KeyValuePair < string , object > ) . IsAssignableFrom ( genericType ) )
98- {
99- _writer . Write ( newLine ) ;
100- this . _writer . Flush ( ) ;
101- return ;
102- }
103-
104- mode = "Properties" ;
105- props = CustomPropertyHelper . GetSaveAsProperties ( genericType , _configuration ) ;
106- }
107- else
58+ if ( rowBuilder . Length == 0 )
10859 {
109- var firstItem = enumerator . Current ;
110- if ( firstItem is IDictionary < string , object > genericDic )
111- {
112- mode = "IDictionary<string, object>" ;
113- props = CustomPropertyHelper . GetDictionaryColumnInfo ( genericDic , null , _configuration ) ;
114- }
115- else if ( firstItem is IDictionary dic )
116- {
117- mode = "IDictionary" ;
118- props = CustomPropertyHelper . GetDictionaryColumnInfo ( null , dic , _configuration ) ;
119- mode = "IDictionary" ;
120- }
121- else
122- {
123- mode = "Properties" ;
124- genericType = firstItem . GetType ( ) ;
125- props = CustomPropertyHelper . GetSaveAsProperties ( genericType , _configuration ) ;
126- }
127- }
128-
129- if ( this . _printHeader )
130- {
131- _writer . Write ( string . Join ( seperator , props . Select ( s => CsvHelpers . ConvertToCsvValue ( s ? . ExcelColumnName , _configuration . AlwaysQuote , _configuration . Seperator ) ) ) ) ;
132- _writer . Write ( newLine ) ;
133- }
134-
135- if ( ! empty )
136- {
137- if ( mode == "IDictionary<string, object>" ) //Dapper Row
138- GenerateSheetByDapperRow ( _writer , enumerator , props . Select ( x => x . Key . ToString ( ) ) . ToList ( ) , seperator , newLine ) ;
139- else if ( mode == "IDictionary" ) //IDictionary
140- GenerateSheetByIDictionary ( _writer , enumerator , props . Select ( x => x . Key ) . ToList ( ) , seperator , newLine ) ;
141- else if ( mode == "Properties" )
142- GenerateSheetByProperties ( _writer , enumerator , props , seperator , newLine ) ;
143- else
144- throw new NotImplementedException ( $ "Mode for genericType { genericType ? . Name } not Implemented. please issue for me.") ;
60+ return ;
14561 }
62+ rowBuilder . Remove ( rowBuilder . Length - 1 , 1 ) ;
14663 }
14764
148- private void GenerateSheetByIDataReader ( IDataReader reader , string seperator , string newLine , StreamWriter writer )
65+ private string GetHeader ( List < ExcelColumnInfo > props ) => string . Join (
66+ _configuration . Seperator . ToString ( ) ,
67+ props . Select ( s => CsvHelpers . ConvertToCsvValue ( s ? . ExcelColumnName , _configuration . AlwaysQuote , _configuration . Seperator ) ) ) ;
68+
69+ private void WriteValues ( StreamWriter writer , object values )
14970 {
150- int fieldCount = reader . FieldCount ;
151- if ( fieldCount == 0 )
152- throw new InvalidDataException ( "fieldCount is 0" ) ;
71+ IMiniExcelWriteAdapter writeAdapter = MiniExcelWriteAdapterFactory . GetWriteAdapter ( values , _configuration ) ;
15372
154- if ( this . _printHeader )
73+ var props = writeAdapter . GetColumns ( ) ;
74+ if ( props == null )
15575 {
156- for ( int i = 0 ; i < fieldCount ; i ++ )
157- {
158- var columnName = reader . GetName ( i ) ;
76+ _writer . Write ( _configuration . NewLine ) ;
77+ _writer . Flush ( ) ;
78+ return ;
79+ }
15980
160- if ( i != 0 )
161- writer . Write ( seperator ) ;
162- writer . Write ( CsvHelpers . ConvertToCsvValue ( ToCsvString ( columnName , null ) , _configuration . AlwaysQuote , _configuration . Seperator ) ) ;
163- }
164- writer . Write ( newLine ) ;
81+ if ( _printHeader )
82+ {
83+ _writer . Write ( GetHeader ( props ) ) ;
84+ _writer . Write ( _configuration . NewLine ) ;
16585 }
16686
167- while ( reader . Read ( ) )
87+ var rowBuilder = new StringBuilder ( ) ;
88+ if ( writeAdapter != null )
16889 {
169- for ( int i = 0 ; i < fieldCount ; i ++ )
90+ foreach ( var row in writeAdapter . GetRows ( props ) )
17091 {
171- var cellValue = reader . GetValue ( i ) ;
172- if ( i != 0 )
173- writer . Write ( seperator ) ;
174- writer . Write ( CsvHelpers . ConvertToCsvValue ( ToCsvString ( cellValue , null ) , _configuration . AlwaysQuote , _configuration . Seperator ) ) ;
92+ rowBuilder . Clear ( ) ;
93+ foreach ( var column in row )
94+ {
95+ AppendColumn ( rowBuilder , column ) ;
96+ }
97+ RemoveTrailingSeparator ( rowBuilder ) ;
98+ _writer . Write ( rowBuilder . ToString ( ) ) ;
99+ _writer . Write ( _configuration . NewLine ) ;
175100 }
176- writer . Write ( newLine ) ;
177101 }
178102 }
179103
180- private void GenerateSheetByDataTable ( StreamWriter writer , DataTable dt , string seperator , string newLine )
104+ private async Task WriteValuesAsync ( StreamWriter writer , object values , string seperator , string newLine , CancellationToken cancellationToken )
181105 {
106+ #if NETSTANDARD2_0_OR_GREATER || NET
107+ IMiniExcelWriteAdapter writeAdapter = null ;
108+ if ( ! MiniExcelWriteAdapterFactory . TryGetAsyncWriteAdapter ( values , _configuration , out var asyncWriteAdapter ) )
109+ {
110+ writeAdapter = MiniExcelWriteAdapterFactory . GetWriteAdapter ( values , _configuration ) ;
111+ }
112+ var props = writeAdapter != null ? writeAdapter . GetColumns ( ) : await asyncWriteAdapter . GetColumnsAsync ( ) ;
113+ #else
114+ IMiniExcelWriteAdapter writeAdapter = MiniExcelWriteAdapterFactory . GetWriteAdapter ( values , _configuration ) ;
115+ var props = writeAdapter . GetColumns ( ) ;
116+ #endif
117+ if ( props == null )
118+ {
119+ await _writer . WriteAsync ( _configuration . NewLine ) ;
120+ await _writer . FlushAsync ( ) ;
121+ return ;
122+ }
182123 if ( _printHeader )
183124 {
184- writer . Write ( string . Join ( seperator , dt . Columns . Cast < DataColumn > ( ) . Select ( s => CsvHelpers . ConvertToCsvValue ( s . Caption ?? s . ColumnName , _configuration . AlwaysQuote , _configuration . Seperator ) ) ) ) ;
185- writer . Write ( newLine ) ;
125+ await _writer . WriteAsync ( GetHeader ( props ) ) ;
126+ await _writer . WriteAsync ( newLine ) ;
186127 }
187- for ( int i = 0 ; i < dt . Rows . Count ; i ++ )
128+ var rowBuilder = new StringBuilder ( ) ;
129+ if ( writeAdapter != null )
188130 {
189- var first = true ;
190- for ( int j = 0 ; j < dt . Columns . Count ; j ++ )
131+ foreach ( var row in writeAdapter . GetRows ( props , cancellationToken ) )
191132 {
192- var cellValue = CsvHelpers . ConvertToCsvValue ( ToCsvString ( dt . Rows [ i ] [ j ] , null ) , _configuration . AlwaysQuote , _configuration . Seperator ) ;
193- if ( ! first )
194- writer . Write ( seperator ) ;
195- writer . Write ( cellValue ) ;
196- first = false ;
133+ rowBuilder . Clear ( ) ;
134+ foreach ( var column in row )
135+ {
136+ AppendColumn ( rowBuilder , column ) ;
137+ }
138+ RemoveTrailingSeparator ( rowBuilder ) ;
139+ await _writer . WriteAsync ( rowBuilder . ToString ( ) ) ;
140+ await _writer . WriteAsync ( newLine ) ;
197141 }
198- writer . Write ( newLine ) ;
199142 }
200- }
201-
202- private void GenerateSheetByProperties ( StreamWriter writer , IEnumerator value , List < ExcelColumnInfo > props , string seperator , string newLine )
203- {
204- do
143+ #if NETSTANDARD2_0_OR_GREATER || NET
144+ else
205145 {
206- var v = value . Current ;
207- var values = props . Select ( s => CsvHelpers . ConvertToCsvValue ( ToCsvString ( s ? . Property . GetValue ( v ) , s ) , _configuration . AlwaysQuote , _configuration . Seperator ) ) ;
208- writer . Write ( string . Join ( seperator , values ) ) ;
209- writer . Write ( newLine ) ;
210- } while ( value . MoveNext ( ) ) ;
146+ await foreach ( var row in asyncWriteAdapter . GetRowsAsync ( props , cancellationToken ) )
147+ {
148+ rowBuilder . Clear ( ) ;
149+ await foreach ( var column in row )
150+ {
151+ AppendColumn ( rowBuilder , column ) ;
152+ }
153+ RemoveTrailingSeparator ( rowBuilder ) ;
154+ await _writer . WriteAsync ( rowBuilder . ToString ( ) ) ;
155+ await _writer . WriteAsync ( newLine ) ;
156+ }
157+ }
158+ #endif
211159 }
212160
213- private void GenerateSheetByIDictionary ( StreamWriter writer , IEnumerator value , List < object > keys , string seperator , string newLine )
161+ public async Task SaveAsAsync ( CancellationToken cancellationToken = default )
214162 {
215- do
163+ var seperator = _configuration . Seperator . ToString ( ) ;
164+ var newLine = _configuration . NewLine ;
165+
166+ if ( _value == null )
216167 {
217- var v = ( IDictionary ) value . Current ;
218- var values = keys . Select ( key => CsvHelpers . ConvertToCsvValue ( ToCsvString ( v [ key ] , null ) , _configuration . AlwaysQuote , _configuration . Seperator ) ) ;
219- writer . Write ( string . Join ( seperator , values ) ) ;
220- writer . Write ( newLine ) ;
221- } while ( value . MoveNext ( ) ) ;
168+ await _writer . WriteAsync ( "" ) ;
169+ await _writer . FlushAsync ( ) ;
170+ return ;
171+ }
172+
173+ await WriteValuesAsync ( _writer , _value , seperator , newLine , cancellationToken ) ;
174+ await _writer . FlushAsync ( ) ;
222175 }
223176
224- private void GenerateSheetByDapperRow ( StreamWriter writer , IEnumerator value , List < string > keys , string seperator , string newLine )
177+ public async Task InsertAsync ( bool overwriteSheet = false , CancellationToken cancellationToken = default )
225178 {
226- do
227- {
228- var v = ( IDictionary < string , object > ) value . Current ;
229- var values = keys . Select ( key => CsvHelpers . ConvertToCsvValue ( ToCsvString ( v [ key ] , null ) , _configuration . AlwaysQuote , _configuration . Seperator ) ) ;
230- writer . Write ( string . Join ( seperator , values ) ) ;
231- writer . Write ( newLine ) ;
232- } while ( value . MoveNext ( ) ) ;
179+ await SaveAsAsync ( cancellationToken ) ;
233180 }
234181
235182 public string ToCsvString ( object value , ExcelColumnInfo p )
0 commit comments