C#的Excel導入、導出


這篇文章主要為大家詳細介紹了C#的Excel導入、導出的相關資料,需要的朋友可以參考下

本篇主要介紹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

以上就是本文的全部內容,希望能夠對大家的學習有所幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM