Excel导入及导出问题产生:
从接触.net到现在一直在维护一个DataTable导出到Excel的类,时不时还会维护一个导入类。以下是时不时就会出现的问题:
导出问题:
如果是asp.net,你得在服务器端装Office,几百M呢,还得及时更新它,以防漏洞,还得设定权限允许ASP.net访问COM+,听说如果导出过程中出问题可能导致服务器宕机。
Excel会把只包含数字的列进行类型转换,本来是文本型的,它非要把你转成数值型的,像身份证后三位变成000,编号000123会变成123,够智能吧,够郁闷吧。不过这些都还是可以变通解决的,在他们前边加上一个字母,让他们不只包含数字。
导出时,如果你的字段内容以"-"或"="开头,Excel好像把它当成了公式什么的,接下来就出错,提示:类似,保存到Sheet1的问题
导入问题:
Excel会根据你的 Excel文件前8行分析数据类型,如果正好你前8行某一列只是数字,那它会认为你这一列就是数值型的,然后,身份证,手机,编号都转吧变成类似这样的1.42702E+17格式,日期列变成 包含日期和数字的,乱的很,可以通过改注册表让Excel分析整个表,但如果整列都是数字,那这个问题还是解决不了。
以上问题,一般人初次做时肯定得上网查查吧,一个问题接着另一个问题,查到你郁郁而死,还有很多问题没解决,最终感觉已经解决的不错了,但还不能保证某一天还会出个什么问题。
使用第三方开源组件导入及导出Excel的解决方案:
偶然间发现了NPOI与MyXls,相见恨晚,害的我在Excel上浪费了那么多时间,他们俩的好处是:就是.net的自定义类库,可以直接对Excel进行读或写,而不依赖Office 的 Excel,这不管对于ASP.net或Winform都非常有利,不用担心Excel进程的释放问题,服务器安全,设置,导出,导入“Excel智能识别”,公式日期等问题,可以说以前的Excel问题,全都不用管了,它们可以很好的帮你解决,NPOI || MyXls == 研究几年Excel。
NPOI开源地址: http://npoi.codeplex.com/
NPOI中文文档: http://www.cnblogs.com/tonyqus/archive/2009/04/12/1434209.html
MyXls开源地址: http://sourceforge.net/projects/myxls/
下面来两个简单入门例子:
MyXls 快速入门例子:
1
///
<summary>
2
///
MyXls简单Demo,快速入门代码
3
///
</summary>
4
///
<param name="dtSource"></param>
5
///
<param name="strFileName"></param>
6
///
<remarks>
MyXls认为Excel的第一个单元格是:(1,1)
</remarks>
7
///
<Author>
柳永法
http://www.yongfa365.com/
2010-5-8 22:21:41
</Author>
8
public
static
void
ExportEasy(DataTable dtSource,
string
strFileName)
9
{
10
XlsDocument xls
=
new
XlsDocument();
11
Worksheet sheet
=
xls.Workbook.Worksheets.Add(
"
Sheet1
"
);
12
13
//
填充表头
14
foreach
(DataColumn col
in
dtSource.Columns)
15
{
16
sheet.Cells.Add(
1
, col.Ordinal
+
1
, col.ColumnName);
17
}
18
19
//
填充内容
20
for
(
int
i
=
0
; i
<
dtSource.Rows.Count; i
++
)
21
{
22
for
(
int
j
=
0
; j
<
dtSource.Columns.Count; j
++
)
23
{
24
sheet.Cells.Add(i
+
2
, j
+
1
, dtSource.Rows[i][j].ToString());
25
}
26
}
27
28
//
保存
29
xls.FileName
=
strFileName;
30
xls.Save();
31
}
NPOI 快速入门例子:
1
///
<summary>
2
///
NPOI简单Demo,快速入门代码
3
///
</summary>
4
///
<param name="dtSource"></param>
5
///
<param name="strFileName"></param>
6
///
<remarks>
NPOI认为Excel的第一个单元格是:(0,0)
</remarks>
7
///
<Author>
柳永法
http://www.yongfa365.com/
2010-5-8 22:21:41
</Author>
8
public
static
void
ExportEasy(DataTable dtSource,
string
strFileName)
9
{
10
HSSFWorkbook workbook
=
new
HSSFWorkbook();
11
HSSFSheet sheet
=
workbook.CreateSheet();
12
13
//
填充表头
14
HSSFRow dataRow
=
sheet.CreateRow(
0
);
15
foreach
(DataColumn column
in
dtSource.Columns)
16
{
17
dataRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
18
}
19
20
21
//
填充内容
22
for
(
int
i
=
0
; i
<
dtSource.Rows.Count; i
++
)
23
{
24
dataRow
=
sheet.CreateRow(i
+
1
);
25
for
(
int
j
=
0
; j
<
dtSource.Columns.Count; j
++
)
26
{
27
dataRow.CreateCell(j).SetCellValue(dtSource.Rows[i][j].ToString());
28
}
29
}
30
31
32
//
保存
33
using
(MemoryStream ms
=
new
MemoryStream())
34
{
35
using
(FileStream fs
=
new
FileStream(strFileName, FileMode.Create, FileAccess.Write))
36
{
37
workbook.Write(fs);
38
}
39
}
40
workbook.Dispose();
41
}
接下来是 柳永法(yongfa365)'Blog封装的可以用在实际项目中的类,实现的功能有(仅NPOI):
- 支持web及winform从DataTable导出到Excel。
- 生成速度很快。
- 准确判断数据类型,不会出现身份证转数值等上面提到的一系列问题。
- 如果单页条数大于65535时会新建工作表。
- 列宽自适应。
- 支持读取Excel。
- 调用方便,只一调用一个静态类就OK了。
- 因为测试期间发现MyXls导出速度要比NPOI慢3倍,而NPOI既能满足我们的导出需求,又能很好的满足我们的导入需求,所以只针对NPOI进行全方位功能实现及优化。
MyXls导出相关类:
1
using
System;
2
using
System.Collections.Generic;
3
using
System.Linq;
4
using
System.Text;
5
using
org.in2bits.MyXls;
6
using
org.in2bits.MyXls.ByteUtil;
7
using
System.Data;
8
9
class
ExcelHelper
10
{
11
public
static
void
Export(DataTable dtSource,
string
strHeaderText,
string
strFileName)
12
{
13
XlsDocument xls
=
new
XlsDocument();
14
xls.FileName
=
DateTime.Now.ToString(
"
yyyyMMddHHmmssffff
"
, System.Globalization.DateTimeFormatInfo.InvariantInfo);
15
xls.SummaryInformation.Author
=
"
yongfa365
"
;
//
填加xls文件作者信息
16
xls.SummaryInformation.NameOfCreatingApplication
=
"
liu yongfa
"
;
//
填加xls文件创建程序信息
17
xls.SummaryInformation.LastSavedBy
=
"
LastSavedBy
"
;
//
填加xls文件最后保存者信息
18
xls.SummaryInformation.Comments
=
"
Comments
"
;
//
填加xls文件作者信息
19
xls.SummaryInformation.Title
=
"
title
"
;
//
填加xls文件标题信息
20
xls.SummaryInformation.Subject
=
"
Subject
"
;
//
填加文件主题信息
21
xls.DocumentSummaryInformation.Company
=
"
company
"
;
//
填加文件公司信息
22
23
24
Worksheet sheet
=
xls.Workbook.Worksheets.Add(
"
Sheet1
"
);
//
状态栏标题名称
25
Cells cells
=
sheet.Cells;
26
27
foreach
(DataColumn col
in
dtSource.Columns)
28
{
29
Cell cell
=
cells.Add(
1
, col.Ordinal
+
1
, col.ColumnName);
30
cell.Font.FontFamily
=
FontFamilies.Roman;
//
字体
31
cell.Font.Bold
=
true
;
//
字体为粗体
32
33
}
34
#region
填充内容
35
XF dateStyle
=
xls.NewXF();
36
dateStyle.Format
=
"
yyyy-mm-dd
"
;
37
38
for
(
int
i
=
0
; i
<
dtSource.Rows.Count; i
++
)
39
{
40
for
(
int
j
=
0
; j
<
dtSource.Columns.Count; j
++
)
41
{
42
43
int
rowIndex
=
i
+
2
;
44
int
colIndex
=
j
+
1
;
45
string
drValue
=
dtSource.Rows[i][j].ToString();
46
47
switch
(dtSource.Rows[i][j].GetType().ToString())
48
{
49
case
"
System.String
"
:
//
字符串类型
50
cells.Add(rowIndex, colIndex, drValue);
51
break
;
52
case
"
System.DateTime
"
:
//
日期类型
53
DateTime dateV;
54
DateTime.TryParse(drValue,
out
dateV);
55
cells.Add(rowIndex, colIndex, dateV, dateStyle);
56
break
;
57
case
"
System.Boolean
"
:
//
布尔型
58
bool
boolV
=
false
;
59
bool
.TryParse(drValue,
out
boolV);
60
cells.Add(rowIndex, colIndex, boolV);
61
break
;
62
case
"
System.Int16
"
:
//
整型
63
case
"
System.Int32
"
:
64
case
"
System.Int64
"
:
65
case
"
System.Byte
"
:
66
int
intV
=
0
;
67
int
.TryParse(drValue,
out
intV);
68
cells.Add(rowIndex, colIndex, intV);
69
break
;
70
case
"
System.Decimal
"
:
//
浮点型
71
case
"
System.Double
"
:
72
double
doubV
=
0
;
73
double
.TryParse(drValue,
out
doubV);
74
cells.Add(rowIndex, colIndex, doubV);
75
break
;
76
case
"
System.DBNull
"
:
//
空值处理
77
cells.Add(rowIndex, colIndex,
null
);
78
break
;
79
default
:
80
cells.Add(rowIndex, colIndex,
null
);
81
break
;
82
}
83
}
84
}
85
86
#endregion
87
88
xls.FileName
=
strFileName;
89
xls.Save();
90
}
91
}
92
NPOI导入导出相关类:
1
using
System;
2
using
System.Collections.Generic;
3
using
System.Data;
4
using
System.IO;
5
using
System.Text;
6
using
System.Web;
7
using
NPOI;
8
using
NPOI.HPSF;
9
using
NPOI.HSSF;
10
using
NPOI.HSSF.UserModel;
11
using
NPOI.HSSF.Util;
12
using
NPOI.POIFS;
13
using
NPOI.Util;
14
15
16
public
class
ExcelHelper
17
{
18
///
<summary>
19
///
DataTable导出到Excel文件
20
///
</summary>
21
///
<param name="dtSource">
源DataTable
</param>
22
///
<param name="strHeaderText">
表头文本
</param>
23
///
<param name="strFileName">
保存位置
</param>
24
///
<Author>
柳永法
http://www.yongfa365.com/
2010-5-8 22:21:41
</Author>
25
public
static
void
Export(DataTable dtSource,
string
strHeaderText,
string
strFileName)
26
{
27
using
(MemoryStream ms
=
Export(dtSource, strHeaderText))
28
{
29
using
(FileStream fs
=
new
FileStream(strFileName, FileMode.Create, FileAccess.Write))
30
{
31
byte
[] data
=
ms.ToArray();
32
fs.Write(data,
0
, data.Length);
33
fs.Flush();
34
}
35
}
36
}
37
38
///
<summary>
39
///
DataTable导出到Excel的MemoryStream
40
///
</summary>
41
///
<param name="dtSource">
源DataTable
</param>
42
///
<param name="strHeaderText">
表头文本
</param>
43
///
<Author>
柳永法
http://www.yongfa365.com/
2010-5-8 22:21:41
</Author>
44
public
static
MemoryStream Export(DataTable dtSource,
string
strHeaderText)
45
{
46
HSSFWorkbook workbook
=
new
HSSFWorkbook();
47
HSSFSheet sheet
=
workbook.CreateSheet();
48
49
#region
右击文件 属性信息
50
{
51
DocumentSummaryInformation dsi
=
PropertySetFactory.CreateDocumentSummaryInformation();
52
dsi.Company
=
"
http://www.yongfa365.com/
"
;
53
workbook.DocumentSummaryInformation
=
dsi;
54
55
SummaryInformation si
=
PropertySetFactory.CreateSummaryInformation();
56
si.Author
=
"
柳永法
"
;
//
填加xls文件作者信息
57
si.ApplicationName
=
"
NPOI测试程序
"
;
//
填加xls文件创建程序信息
58
si.LastAuthor
=
"
柳永法2
"
;
//
填加xls文件最后保存者信息
59
si.Comments
=
"
说明信息
"
;
//
填加xls文件作者信息
60
si.Title
=
"
NPOI测试
"
;
//
填加xls文件标题信息
61
si.Subject
=
"
NPOI测试Demo
"
;
//
填加文件主题信息
62
si.CreateDateTime
=
DateTime.Now;
63
workbook.SummaryInformation
=
si;
64
}
65
#endregion
66
67
HSSFCellStyle dateStyle
=
workbook.CreateCellStyle();
68
HSSFDataFormat format
=
workbook.CreateDataFormat();
69
dateStyle.DataFormat
=
format.GetFormat(
"
yyyy-mm-dd
"
);
70
71
//
取得列宽
72
int
[] arrColWidth
=
new
int
[dtSource.Columns.Count];
73
foreach
(DataColumn item
in
dtSource.Columns)
74
{
75
arrColWidth[item.Ordinal]
=
Encoding.GetEncoding(
936
).GetBytes(item.ColumnName.ToString()).Length;
76
}
77
for
(
int
i
=
0
; i
<
dtSource.Rows.Count; i
++
)
78
{
79
for
(
int
j
=
0
; j
<
dtSource.Columns.Count; j
++
)
80
{
81
int
intTemp
=
Encoding.GetEncoding(
936
).GetBytes(dtSource.Rows[i][j].ToString()).Length;
82
if
(intTemp
>
arrColWidth[j])
83
{
84
arrColWidth[j]
=
intTemp;
85
}
86
}
87
}
88
89
90
91
int
rowIndex
=
0
;
92
93
foreach
(DataRow row
in
dtSource.Rows)
94
{
95
#region
新建表,填充表头,填充列头,样式
96
if
(rowIndex
==
65535
||
rowIndex
==
0
)
97
{
98
if
(rowIndex
!=
0
)
99
{
100
sheet
=
workbook.CreateSheet();
101
}
102
103
#region
表头及样式
104
{
105
HSSFRow headerRow
=
sheet.CreateRow(
0
);
106
headerRow.HeightInPoints
=
25
;
107
headerRow.CreateCell(
0
).SetCellValue(strHeaderText);
108
109
HSSFCellStyle headStyle
=
workbook.CreateCellStyle();
110
headStyle.Alignment
=
CellHorizontalAlignment.CENTER;
111
HSSFFont font
=
workbook.CreateFont();
112
font.FontHeightInPoints
=
20
;
113
font.Boldweight
=
700
;
114
headStyle.SetFont(font);
115
116
headerRow.GetCell(
0
).CellStyle
=
headStyle;
117
118
sheet.AddMergedRegion(
new
Region(
0
,
0
,
0
, dtSource.Columns.Count
-
1
));
119
headerRow.Dispose();
120
}
121
#endregion
122
123
124
#region
列头及样式
125
{
126
HSSFRow headerRow
=
sheet.CreateRow(
1
);
127
128
129
HSSFCellStyle headStyle
=
workbook.CreateCellStyle();
130
headStyle.Alignment
=
CellHorizontalAlignment.CENTER;
131
HSSFFont font
=
workbook.CreateFont();
132
font.FontHeightInPoints
=
10
;
133
font.Boldweight
=
700
;
134
headStyle.SetFont(font);
135
136
137
foreach
(DataColumn column
in
dtSource.Columns)
138
{
139
headerRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
140
headerRow.GetCell(column.Ordinal).CellStyle
=
headStyle;
141
142
//
设置列宽
143
sheet.SetColumnWidth(column.Ordinal, (arrColWidth[column.Ordinal]
+
1
)
*
256
);
144
145
}
146
headerRow.Dispose();
147
}
148
#endregion
149
150
rowIndex
=
2
;
151
}
152
#endregion
153
154
155
#region
填充内容
156
HSSFRow dataRow
=
sheet.CreateRow(rowIndex);
157
foreach
(DataColumn column
in
dtSource.Columns)
158
{
159
HSSFCell newCell
=
dataRow.CreateCell(column.Ordinal);
160
161
string
drValue
=
row[column].ToString();
162
163
switch
(column.DataType.ToString())
164
{
165
case
"
System.String
"
:
//
字符串类型
166
newCell.SetCellValue(drValue);
167
break
;
168
case
"
System.DateTime
"
:
//
日期类型
169
DateTime dateV;
170
DateTime.TryParse(drValue,
out
dateV);
171
newCell.SetCellValue(dateV);
172
173
newCell.CellStyle
=
dateStyle;
//
格式化显示
174
break
;
175
case
"
System.Boolean
"
:
//
布尔型
176
bool
boolV
=
false
;
177
bool
.TryParse(drValue,
out
boolV);
178
newCell.SetCellValue(boolV);
179
break
;
180
case
"
System.Int16
"
:
//
整型
181
case
"
System.Int32
"
:
182
case
"
System.Int64
"
:
183
case
"
System.Byte
"
:
184
int
intV
=
0
;
185
int
.TryParse(drValue,
out
intV);
186
newCell.SetCellValue(intV);
187
break
;
188
case
"
System.Decimal
"
:
//
浮点型
189
case
"
System.Double
"
:
190
double
doubV
=
0
;
191
double
.TryParse(drValue,
out
doubV);
192
newCell.SetCellValue(doubV);
193
break
;
194
case
"
System.DBNull
"
:
//
空值处理
195
newCell.SetCellValue(
""
);
196
break
;
197
default
:
198
newCell.SetCellValue(
""
);
199
break
;
200
}
201
202
}
203
#endregion
204
205
rowIndex
++
;
206
}
207
208
209
using
(MemoryStream ms
=
new
MemoryStream())
210
{
211
workbook.Write(ms);
212
ms.Flush();
213
ms.Position
=
0
;
214
215
sheet.Dispose();
216
//
workbook.Dispose();
//
一般只用写这一个就OK了,他会遍历并释放所有资源,但当前版本有问题所以只释放sheet
217
return
ms;
218
}
219
220
}
221
222
223
///
<summary>
224
///
用于Web导出
225
///
</summary>
226
///
<param name="dtSource">
源DataTable
</param>
227
///
<param name="strHeaderText">
表头文本
</param>
228
///
<param name="strFileName">
文件名
</param>
229
///
<Author>
柳永法
http://www.yongfa365.com/
2010-5-8 22:21:41
</Author>
230
public
static
void
ExportByWeb(DataTable dtSource,
string
strHeaderText,
string
strFileName)
231
{
232
233
HttpContext curContext
=
HttpContext.Current;
234
235
//
设置编码和附件格式
236
curContext.Response.ContentType
=
"
application/vnd.ms-excel
"
;
237
curContext.Response.ContentEncoding
=
Encoding.UTF8;
238
curContext.Response.Charset
=
""
;
239
curContext.Response.AppendHeader(
"
Content-Disposition
"
,
240
"
attachment;filename=
"
+
HttpUtility.UrlEncode(strFileName, Encoding.UTF8));
241
242
curContext.Response.BinaryWrite(Export(dtSource, strHeaderText).GetBuffer());
243
curContext.Response.End();
244
245
}
246
247
248
///
<summary>
读取excel
249
///
默认第一行为标头
250
///
</summary>
251
///
<param name="strFileName">
excel文档路径
</param>
252
///
<returns></returns>
253
public
static
DataTable Import(
string
strFileName)
254
{
255
DataTable dt
=
new
DataTable();
256
257
HSSFWorkbook hssfworkbook;
258
using
(FileStream file
=
new
FileStream(strFileName, FileMode.Open, FileAccess.Read))
259
{
260
hssfworkbook
=
new
HSSFWorkbook(file);
261
}
262
HSSFSheet sheet
=
hssfworkbook.GetSheetAt(
0
);
263
System.Collections.IEnumerator rows
=
sheet.GetRowEnumerator();
264
265
HSSFRow headerRow
=
sheet.GetRow(
0
);
266
int
cellCount
=
headerRow.LastCellNum;
267
268
for
(
int
j
=
0
; j
<
cellCount; j
++
)
269
{
270
HSSFCell cell
=
headerRow.GetCell(j);
271
dt.Columns.Add(cell.ToString());
272
}
273
274
for
(
int
i
=
(sheet.FirstRowNum
+
1
); i
<=
sheet.LastRowNum; i
++
)
275
{
276
HSSFRow row
=
sheet.GetRow(i);
277
DataRow dataRow
=
dt.NewRow();
278
279
for
(
int
j
=
row.FirstCellNum; j
<
cellCount; j
++
)
280
{
281
if
(row.GetCell(j)
!=
null
)
282
dataRow[j]
=
row.GetCell(j).ToString();
283
}
284
285
dt.Rows.Add(dataRow);
286
}
287
return
dt;
288
}
289
290
}
以上相关源码及测试用例下载地址:
http://download.csdn.net/source/2330821
参考地址:
NPOI导出Excel表功能实现(多个工作簿): http://www.cnblogs.com/zhengjuzhuan/archive/2010/02/01/1661103.html
在 Server 端存取 Excel 檔案的利器:NPOI Library: http://msdn.microsoft.com/zh-tw/ee818993.aspx
ASP.NET使用NPOI类库导出Excel: http://www.cnblogs.com/niunan/archive/2010/03/30/1700706.html
总结:
通过以上分析,我们不难发现,用NPOI或MyXls代替是Excel是很明智的,在发文前,我看到NPOI及MyXls仍然在活跃的更新中。在使用过程中发现这两个组件极相似,以前看过文章说他们使用的内核是一样的。还有NPOI是国人开发的,且有相关中文文档,在很多地方有相关引用,下载量也很大。并且它支持Excel,看到MyXls相关问题基本上没人回答,所以推荐使用NPOI。MyXls可以直接Cell.Font.Bold操作,而NPOI得使用CellType多少感觉有点麻烦。
转自:http://www.cnblogs.com/yongfa365/archive/2010/05/10/NPOI-MyXls-DataTable-To-Excel-From-Excel.html