1
1
using MiniExcelLibs . Utils ;
2
+ using MiniExcelLibs . WriteAdapter ;
2
3
using System ;
3
- using System . Collections ;
4
4
using System . Collections . Generic ;
5
- using System . Data ;
6
5
using System . Globalization ;
7
6
using System . IO ;
8
7
using System . Linq ;
8
+ using System . Text ;
9
9
using System . Threading ;
10
10
using System . Threading . Tasks ;
11
11
@@ -31,205 +31,152 @@ public CsvWriter(Stream stream, object value, IConfiguration configuration, bool
31
31
32
32
public void SaveAs ( )
33
33
{
34
- var seperator = _configuration . Seperator . ToString ( ) ;
35
- var newLine = _configuration . NewLine ;
34
+ if ( _value == null )
36
35
{
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 ;
64
39
}
65
- }
66
40
67
- public async Task SaveAsAsync ( CancellationToken cancellationToken = default )
68
- {
69
- await Task . Run ( ( ) => SaveAs ( ) , cancellationToken ) . ConfigureAwait ( false ) ;
41
+ WriteValues ( _writer , _value ) ;
42
+ _writer . Flush ( ) ;
70
43
}
71
44
72
45
public void Insert ( bool overwriteSheet = false )
73
46
{
74
47
SaveAs ( ) ;
75
48
}
76
49
77
- public async Task InsertAsync ( bool overwriteSheet = false , CancellationToken cancellationToken = default )
50
+ private void AppendColumn ( StringBuilder rowBuilder , CellWriteInfo column )
78
51
{
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 ) ;
80
54
}
81
55
82
- private void GenerateSheetByIEnumerable ( IEnumerable values , string seperator , string newLine , StreamWriter writer )
56
+ private void RemoveTrailingSeparator ( StringBuilder rowBuilder )
83
57
{
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 )
108
59
{
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 ;
145
61
}
62
+ rowBuilder . Remove ( rowBuilder . Length - 1 , 1 ) ;
146
63
}
147
64
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 )
149
70
{
150
- int fieldCount = reader . FieldCount ;
151
- if ( fieldCount == 0 )
152
- throw new InvalidDataException ( "fieldCount is 0" ) ;
71
+ IMiniExcelWriteAdapter writeAdapter = MiniExcelWriteAdapterFactory . GetWriteAdapter ( values , _configuration ) ;
153
72
154
- if ( this . _printHeader )
73
+ var props = writeAdapter . GetColumns ( ) ;
74
+ if ( props == null )
155
75
{
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
+ }
159
80
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 ) ;
165
85
}
166
86
167
- while ( reader . Read ( ) )
87
+ var rowBuilder = new StringBuilder ( ) ;
88
+ if ( writeAdapter != null )
168
89
{
169
- for ( int i = 0 ; i < fieldCount ; i ++ )
90
+ foreach ( var row in writeAdapter . GetRows ( props ) )
170
91
{
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 ) ;
175
100
}
176
- writer . Write ( newLine ) ;
177
101
}
178
102
}
179
103
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 )
181
105
{
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
+ }
182
123
if ( _printHeader )
183
124
{
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 ) ;
186
127
}
187
- for ( int i = 0 ; i < dt . Rows . Count ; i ++ )
128
+ var rowBuilder = new StringBuilder ( ) ;
129
+ if ( writeAdapter != null )
188
130
{
189
- var first = true ;
190
- for ( int j = 0 ; j < dt . Columns . Count ; j ++ )
131
+ foreach ( var row in writeAdapter . GetRows ( props , cancellationToken ) )
191
132
{
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 ) ;
197
141
}
198
- writer . Write ( newLine ) ;
199
142
}
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
205
145
{
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
211
159
}
212
160
213
- private void GenerateSheetByIDictionary ( StreamWriter writer , IEnumerator value , List < object > keys , string seperator , string newLine )
161
+ public async Task SaveAsAsync ( CancellationToken cancellationToken = default )
214
162
{
215
- do
163
+ var seperator = _configuration . Seperator . ToString ( ) ;
164
+ var newLine = _configuration . NewLine ;
165
+
166
+ if ( _value == null )
216
167
{
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 ( ) ;
222
175
}
223
176
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 )
225
178
{
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 ) ;
233
180
}
234
181
235
182
public string ToCsvString ( object value , ExcelColumnInfo p )
0 commit comments