本篇主要介紹C#的Excel導入、導出,供大家參考,具體內容如下
一. 介紹
1.1 第三方類庫:NPOI
說明:NPOI是POI項目的.NET 版本,可用於Excel、Word的讀寫操作。
優點:不用裝Office環境。
下載地址:http://npoi.codeplex.com/releases
1.2 Excel結構介紹
工作簿(Workbook):每個Excel文件可理解為一個工作簿。
工作表(Sheet):一個工作簿(Workbook)可以包含多個工作表。
行(row):一個工作表(Sheet)可以包含多個行。
二. Excel導入
2.1 操作流程
2.2 NPOI操作代碼
說明:把Excel文件轉換為List<T>
步驟:
①讀取Excel文件並以此初始化一個工作簿(Workbook);
②從工作簿上獲取一個工作表(Sheet);默認為工作薄的第一個工作表;
③遍歷工作表所有的行(row);默認從第二行開始遍歷,第一行(序號0)為單元格頭部;
④遍歷行的每一個單元格(cell),根據一定的規律賦值給對象的屬性。
代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
/// <summary>
/// 從Excel2003取數據並記錄到List集合里
/// </summary>
/// <param name="cellHeard">單元頭的Key和Value:{ { "UserName", "姓名" }, { "Age", "年齡" } };</param>
/// <param name="filePath">保存文件絕對路徑</param>
/// <param name="errorMsg">錯誤信息</param>
/// <returns>轉換好的List對象集合</returns>
private
static
List<T> Excel2003ToEntityList<T>(Dictionary<
string
,
string
> cellHeard,
string
filePath,
out
StringBuilder errorMsg) where T :
new
()
{
errorMsg =
new
StringBuilder();
// 錯誤信息,Excel轉換到實體對象時,會有格式的錯誤信息
List<T> enlist =
new
List<T>();
// 轉換后的集合
List<
string
> keys = cellHeard.Keys.ToList();
// 要賦值的實體對象屬性名稱
try
{
using
(FileStream fs = File.OpenRead(filePath))
{
HSSFWorkbook workbook =
new
HSSFWorkbook(fs);
HSSFSheet sheet = (HSSFSheet)workbook.GetSheetAt(0);
// 獲取此文件第一個Sheet頁
for
(
int
i = 1; i <= sheet.LastRowNum; i++)
// 從1開始,第0行為單元頭
{
// 1.判斷當前行是否空行,若空行就不在進行讀取下一行操作,結束Excel讀取操作
if
(sheet.GetRow(i) ==
null
)
{
break
;
}
T en =
new
T();
string
errStr =
""
;
// 當前行轉換時,是否有錯誤信息,格式為:第1行數據轉換異常:XXX列;
for
(
int
j = 0; j < keys.Count; j++)
{
// 2.若屬性頭的名稱包含'.',就表示是子類里的屬性,那么就要遍歷子類,eg:UserEn.TrueName
if
(keys[j].IndexOf(
"."
) >= 0)
{
// 2.1解析子類屬性
string
[] properotyArray = keys[j].Split(
new
string
[] {
"."
}, StringSplitOptions.RemoveEmptyEntries);
string
subClassName = properotyArray[0];
// '.'前面的為子類的名稱
string
subClassProperotyName = properotyArray[1];
// '.'后面的為子類的屬性名稱
System.Reflection.PropertyInfo subClassInfo = en.GetType().GetProperty(subClassName);
// 獲取子類的類型
if
(subClassInfo !=
null
)
{
// 2.1.1 獲取子類的實例
var subClassEn = en.GetType().GetProperty(subClassName).GetValue(en,
null
);
// 2.1.2 根據屬性名稱獲取子類里的屬性信息
System.Reflection.PropertyInfo properotyInfo = subClassInfo.PropertyType.GetProperty(subClassProperotyName);
if
(properotyInfo !=
null
)
{
try
{
// Excel單元格的值轉換為對象屬性的值,若類型不對,記錄出錯信息
properotyInfo.SetValue(subClassEn, GetExcelCellToProperty(properotyInfo.PropertyType, sheet.GetRow(i).GetCell(j)),
null
);
}
catch
(Exception e)
{
if
(errStr.Length == 0)
{
errStr =
"第"
+ i +
"行數據轉換異常:"
;
}
errStr += cellHeard[keys[j]] +
"列;"
;
}
}
}
}
else
{
// 3.給指定的屬性賦值
System.Reflection.PropertyInfo properotyInfo = en.GetType().GetProperty(keys[j]);
if
(properotyInfo !=
null
)
{
try
{
// Excel單元格的值轉換為對象屬性的值,若類型不對,記錄出錯信息
properotyInfo.SetValue(en, GetExcelCellToProperty(properotyInfo.PropertyType, sheet.GetRow(i).GetCell(j)),
null
);
}
catch
(Exception e)
{
if
(errStr.Length == 0)
{
errStr =
"第"
+ i +
"行數據轉換異常:"
;
}
errStr += cellHeard[keys[j]] +
"列;"
;
}
}
}
}
// 若有錯誤信息,就添加到錯誤信息里
if
(errStr.Length > 0)
{
errorMsg.AppendLine(errStr);
}
enlist.Add(en);
}
}
return
enlist;
}
catch
(Exception ex)
{
throw
ex;
}
}
|
2.3 C#邏輯操作代碼
說明:對Excel轉換后的List<T>進行后續操作;如:檢測有效性、持久化存儲等等
步驟:
①調用2.2代碼,把Excel文件轉換為List<T>。
②對List<T>進行有效性檢測:必填項是否為空、是否有重復記錄等等。
③對List<T>進行持久化存儲操作。如:存儲到數據庫。
④返回操作結果。
代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
public
void
ImportExcel(HttpContext context)
{
StringBuilder errorMsg =
new
StringBuilder();
// 錯誤信息
try
{
#region 1.獲取Excel文件並轉換為一個List集合
// 1.1存放Excel文件到本地服務器
HttpPostedFile filePost = context.Request.Files[
"filed"
];
// 獲取上傳的文件
string
filePath = ExcelHelper.SaveExcelFile(filePost);
// 保存文件並獲取文件路徑
// 單元格抬頭
// key:實體對象屬性名稱,可通過反射獲取值
// value:屬性對應的中文注解
Dictionary<
string
,
string
> cellheader =
new
Dictionary<
string
,
string
> {
{
"Name"
,
"姓名"
},
{
"Age"
,
"年齡"
},
{
"GenderName"
,
"性別"
},
{
"TranscriptsEn.ChineseScores"
,
"語文成績"
},
{
"TranscriptsEn.MathScores"
,
"數學成績"
},
};
// 1.2解析文件,存放到一個List集合里
List<UserEntity> enlist = ExcelHelper.ExcelToEntityList<UserEntity>(cellheader, filePath,
out
errorMsg);
#endregion
#region 2.對List集合進行有效性校驗
#region 2.1檢測必填項是否必填
for
(
int
i = 0; i < enlist.Count; i++)
{
UserEntity en = enlist[i];
string
errorMsgStr =
"第"
+ (i + 1) +
"行數據檢測異常:"
;
bool
isHaveNoInputValue =
false
;
// 是否含有未輸入項
if
(
string
.IsNullOrEmpty(en.Name))
{
errorMsgStr +=
"姓名列不能為空;"
;
isHaveNoInputValue =
true
;
}
if
(isHaveNoInputValue)
// 若必填項有值未填
{
en.IsExcelVaildateOK =
false
;
errorMsg.AppendLine(errorMsgStr);
}
}
#endregion
#region 2.2檢測Excel中是否有重復對象
for
(
int
i = 0; i < enlist.Count; i++)
{
UserEntity enA = enlist[i];
if
(enA.IsExcelVaildateOK ==
false
)
// 上面驗證不通過,不進行此步驗證
{
continue
;
}
for
(
int
j = i + 1; j < enlist.Count; j++)
{
UserEntity enB = enlist[j];
// 判斷必填列是否全部重復
if
(enA.Name == enB.Name)
{
enA.IsExcelVaildateOK =
false
;
enB.IsExcelVaildateOK =
false
;
errorMsg.AppendLine(
"第"
+ (i + 1) +
"行與第"
+ (j + 1) +
"行的必填列重復了"
);
}
}
}
#endregion
// TODO:其他檢測
#endregion
// 3.TODO:對List集合持久化存儲操作。如:存儲到數據庫
// 4.返回操作結果
bool
isSuccess =
false
;
if
(errorMsg.Length == 0)
{
isSuccess =
true
;
// 若錯誤信息成都為空,表示無錯誤信息
}
var rs =
new
{ success = isSuccess, msg = errorMsg.ToString(), data = enlist };
System.Web.Script.Serialization.JavaScriptSerializer js =
new
System.Web.Script.Serialization.JavaScriptSerializer();
context.Response.ContentType =
"text/plain"
;
context.Response.Write(js.Serialize(rs));
// 返回Json格式的內容
}
catch
(Exception ex)
{
throw
ex;
}
}
|
3. Excel導出
3.1 導出流程
3.2 NPOI操作代碼
說明:把List<T>轉換為Excel
步驟:
①創建一個工作簿(Workbook);
②在工作簿上創建一個工作表(Sheet);
③在工作表上創建第一行(row),第一行為列頭,依次寫入cellHeard的值(做為列名)。
④循環遍歷List<T>集合,每循環一遍創建一個行(row),然后根據cellHeard的鍵(屬性名稱)依次從List<T>中的實體對象取值存放到單元格內。
代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/// <summary>
/// 實體類集合導出到Excle2003
/// </summary>
/// <param name="cellHeard">單元頭的Key和Value:{ { "UserName", "姓名" }, { "Age", "年齡" } };</param>
/// <param name="enList">數據源</param>
/// <param name="sheetName">工作表名稱</param>
/// <returns>文件的下載地址</returns>
public
static
string
EntityListToExcel2003(Dictionary<
string
,
string
> cellHeard, IList enList,
string
sheetName)
{
try
{
string
fileName = sheetName +
"-"
+ DateTime.Now.ToString(
"yyyyMMddHHmmssfff"
) +
".xls"
;
// 文件名稱
string
urlPath =
"UpFiles/ExcelFiles/"
+ fileName;
// 文件下載的URL地址,供給前台下載
string
filePath = HttpContext.Current.Server.MapPath(
"\\"
+ urlPath);
// 文件路徑
// 1.檢測是否存在文件夾,若不存在就建立個文件夾
string
directoryName = Path.GetDirectoryName(filePath);
if
(!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
// 2.解析單元格頭部,設置單元頭的中文名稱
HSSFWorkbook workbook =
new
HSSFWorkbook();
// 工作簿
ISheet sheet = workbook.CreateSheet(sheetName);
// 工作表
IRow row = sheet.CreateRow(0);
List<
string
> keys = cellHeard.Keys.ToList();
for
(
int
i = 0; i < keys.Count; i++)
{
row.CreateCell(i).SetCellValue(cellHeard[keys[i]]);
// 列名為Key的值
}
// 3.List對象的值賦值到Excel的單元格里
int
rowIndex = 1;
// 從第二行開始賦值(第一行已設置為單元頭)
foreach
(var en
in
enList)
{
IRow rowTmp = sheet.CreateRow(rowIndex);
for
(
int
i = 0; i < keys.Count; i++)
// 根據指定的屬性名稱,獲取對象指定屬性的值
{
string
cellValue =
""
;
// 單元格的值
object
properotyValue =
null
;
// 屬性的值
System.Reflection.PropertyInfo properotyInfo =
null
;
// 屬性的信息
// 3.1 若屬性頭的名稱包含'.',就表示是子類里的屬性,那么就要遍歷子類,eg:UserEn.UserName
if
(keys[i].IndexOf(
"."
) >= 0)
{
// 3.1.1 解析子類屬性(這里只解析1層子類,多層子類未處理)
string
[] properotyArray = keys[i].Split(
new
string
[] {
"."
}, StringSplitOptions.RemoveEmptyEntries);
string
subClassName = properotyArray[0];
// '.'前面的為子類的名稱
string
subClassProperotyName = properotyArray[1];
// '.'后面的為子類的屬性名稱
System.Reflection.PropertyInfo subClassInfo = en.GetType().GetProperty(subClassName);
// 獲取子類的類型
if
(subClassInfo !=
null
)
{
// 3.1.2 獲取子類的實例
var subClassEn = en.GetType().GetProperty(subClassName).GetValue(en,
null
);
// 3.1.3 根據屬性名稱獲取子類里的屬性類型
properotyInfo = subClassInfo.PropertyType.GetProperty(subClassProperotyName);
if
(properotyInfo !=
null
)
{
properotyValue = properotyInfo.GetValue(subClassEn,
null
);
// 獲取子類屬性的值
}
}
}
else
{
// 3.2 若不是子類的屬性,直接根據屬性名稱獲取對象對應的屬性
properotyInfo = en.GetType().GetProperty(keys[i]);
if
(properotyInfo !=
null
)
{
properotyValue = properotyInfo.GetValue(en,
null
);
}
}
// 3.3 屬性值經過轉換賦值給單元格值
if
(properotyValue !=
null
)
{
cellValue = properotyValue.ToString();
// 3.3.1 對時間初始值賦值為空
if
(cellValue.Trim() ==
"0001/1/1 0:00:00"
|| cellValue.Trim() ==
"0001/1/1 23:59:59"
)
{
cellValue =
""
;
}
}
// 3.4 填充到Excel的單元格里
rowTmp.CreateCell(i).SetCellValue(cellValue);
}
rowIndex++;
}
// 4.生成文件
FileStream file =
new
FileStream(filePath, FileMode.Create);
workbook.Write(file);
file.Close();
// 5.返回下載路徑
return
urlPath;
}
catch
(Exception ex)
{
throw
ex;
}
}
|
3.3 C#邏輯操作代碼
說明:對Excel轉換后的List<T>進行后續操作;如:檢測有效性、持久化存儲等等
步驟:
①獲取List<T>集合。
②調用3.2,將List<T>轉換為Excel文件。
③服務器存儲Excel文件並返回下載鏈接。
代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
public
void
ExportExcel(HttpContext context)
{
try
{
// 1.獲取數據集合
List<UserEntity> enlist =
new
List<UserEntity>() {
new
UserEntity{Name=
"劉一"
,Age=22,Gender=
"Male"
,TranscriptsEn=
new
TranscriptsEntity{ChineseScores=80,MathScores=90}},
new
UserEntity{Name=
"陳二"
,Age=23,Gender=
"Male"
,TranscriptsEn=
new
TranscriptsEntity{ChineseScores=81,MathScores=91} },
new
UserEntity{Name=
"張三"
,Age=24,Gender=
"Male"
,TranscriptsEn=
new
TranscriptsEntity{ChineseScores=82,MathScores=92} },
new
UserEntity{Name=
"李四"
,Age=25,Gender=
"Male"
,TranscriptsEn=
new
TranscriptsEntity{ChineseScores=83,MathScores=93} },
new
UserEntity{Name=
"王五"
,Age=26,Gender=
"Male"
,TranscriptsEn=
new
TranscriptsEntity{ChineseScores=84,MathScores=94} },
};
// 2.設置單元格抬頭
// key:實體對象屬性名稱,可通過反射獲取值
// value:Excel列的名稱
Dictionary<
string
,
string
> cellheader =
new
Dictionary<
string
,
string
> {
{
"Name"
,
"姓名"
},
{
"Age"
,
"年齡"
},
{
"GenderName"
,
"性別"
},
{
"TranscriptsEn.ChineseScores"
,
"語文成績"
},
{
"TranscriptsEn.MathScores"
,
"數學成績"
},
};
// 3.進行Excel轉換操作,並返回轉換的文件下載鏈接
string
urlPath = ExcelHelper.EntityListToExcel2003(cellheader, enlist,
"學生成績"
);
System.Web.Script.Serialization.JavaScriptSerializer js =
new
System.Web.Script.Serialization.JavaScriptSerializer();
context.Response.ContentType =
"text/plain"
;
context.Response.Write(js.Serialize(urlPath));
// 返回Json格式的內容
}
catch
(Exception ex)
{
throw
ex;
}
}
|
3.4 代碼分析
核心代碼主要是cellheader與List<T>之間的映射關系:
四. 源碼下載
4.1 運行圖
源碼下載:http://xiazai.jb51.net/201605/yuanma/C#-Excel(jb51.net).rar
以上就是本文的全部內容,希望能夠對大家的學習有所幫助。