最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#通過NPIO讀寫Excel表的方法詳解

 更新時(shí)間:2026年04月24日 08:27:44   作者:火星papa  
文章主要了使用POI用于讀寫Excel文件,對比了NPOI與Microsoft.Office.Interop.Excel的優(yōu)點(diǎn)和缺點(diǎn),文章通過代碼示例展示了使用NPOI讀寫Excel的各類數(shù)據(jù),以及導(dǎo)出ExcelN的方法,通過這些示例,讀者可以了解如何使用POI用于Excel文件的操作,需要的朋友可以參考下

前言

近年一些老舊工程的發(fā)現(xiàn)會(huì)因?yàn)楣こ绦枰褂貌僮鱁xcel表調(diào)用office的接口(Microsoft.Office.Interop.Excel接口),在部分電腦中會(huì)出現(xiàn)無法啟動(dòng)工程、報(bào)COM錯(cuò)誤或者保存文件時(shí)偶爾閃退等異常。這個(gè)問題對應(yīng)使用方確實(shí)是有些痛苦,排查起來也比較困難,可能是部分盜版系統(tǒng)不完整也可能是office版本,也可能是系統(tǒng)設(shè)置問題,如果工程代碼可已重構(gòu)和替換接口,則建議使用NPOI來實(shí)現(xiàn),要穩(wěn)定很多。本文就NPOI的優(yōu)點(diǎn)以及如何使用它讀寫Excel表,并使用代碼描述給大家參考。

Microsoft.Office.Interop.Excel和NPOI的對比

如下表多項(xiàng)對比,可以看出NPOI很是有著較大的優(yōu)勢,大家在讀寫控制Excel表格時(shí),建議優(yōu)先考慮。

對比項(xiàng)Microsoft.Office.Interop.ExcelNPOI
環(huán)境依賴必須安裝 Office,Windows 獨(dú)占無 Office 依賴,跨平臺(tái)(Windows/Linux)
性能與內(nèi)存慢、耗內(nèi)存、易泄漏;大數(shù)據(jù)易卡死快、輕量、穩(wěn)定;大數(shù)據(jù)更友好
并發(fā) / 服務(wù)器極差:單線程、進(jìn)程殘留、權(quán)限問題優(yōu)秀:多線程安全、純內(nèi)存 / 流操作
部署難度高:需安裝 Office、配置 DCOM、權(quán)限低:NuGet 安裝,直接部署
功能完整度最全:VBA、宏、圖表、透視表、函數(shù)等主流功能:樣式、公式、圖表、合并單元格等
版本兼容易出現(xiàn)版本沖突(2016/2019/365)統(tǒng)一 API,無版本問題
授權(quán)需 Office 授權(quán)(服務(wù)器商用需額外許可)開源免費(fèi)(Apache 2.0)
適用場景Windows 桌面、單機(jī)自動(dòng)化、需完整 Excel 特性 服務(wù)器導(dǎo)出 / 導(dǎo)入、Web、跨平臺(tái)、大數(shù)據(jù)
常見坑進(jìn)程殺不掉、文件占用、權(quán)限、COM 異常部分高級(jí)格式 / 函數(shù)需手動(dòng)處理

這里使用VS2022下基于.netFramework4.8.1工程來描述NPOI的部分功能。提示: 下面案例可供參考

一、添加第三方庫

在根據(jù)的net包管理器中找到管理解決方案的netGet程序包(如圖所示)。

在瀏覽中搜索"NPOI”,可以找到人氣最旺的NPIO,可以安裝最新版本,點(diǎn)擊安裝即可。我這里安裝了穩(wěn)定版本2.7.6,已確認(rèn)該版本可以使用。

  • 安裝成功后可以看到NuGet解決方案中已安裝中就有了這個(gè)NPOI項(xiàng)目,并可以點(diǎn)擊卸載。
  • 在工程解決方案資源管理器的引用中也可以看到添加的NPOI項(xiàng)目。

二、代碼描述構(gòu)建函數(shù)

在工程文件中添加一個(gè) ExcelOperation.cs的類文件,就可以開始添加對應(yīng)的接口代碼了。

1、添加引用

除了系統(tǒng)使用的其他引用務(wù)必加上NPOI的幾個(gè)引用

 //工具 → “管理NuGet程序包” → 搜索NPOI(Tony Qu,NPOI Contributors)→ 安裝版本 2.7.6
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

2、讀Excel表功能函數(shù)設(shè)計(jì)

(1) 讀取EXCEL表格所有數(shù)據(jù)到字符串?dāng)?shù)組

  • 可以看到這里通過數(shù)據(jù)流的方式出處Excel表個(gè)內(nèi)容,表單使用的默認(rèn)的第一個(gè)表單,當(dāng)然你也可以以名稱的方式獲取表單。
  • 它是通過首行和首列來獲取行數(shù)和列數(shù)的,所以原始文件不要有首行首列中間為空的情況。
/// <summary>
/// 讀取EXCEL表格所有數(shù)據(jù)到字符串?dāng)?shù)組
/// </summary>
/// <param name="filePath">文件路徑</param>
/// <returns></returns>
public string[] ReadExcelAllToStrs(string filePath)
{ 
     //初始化返回值
    string[] strs = new string[] { };
    try
    {
        //創(chuàng)建Excel文件數(shù)據(jù)流對象
        FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        //創(chuàng)建Excel文件對象
        IWorkbook workbook = new XSSFWorkbook(fileStream);
        //獲取第1個(gè)表單
        ISheet worksheet = workbook.GetSheetAt(0);
        //獲取單元格值行列
        int rowCount = worksheet.LastRowNum + 1;
        Console.WriteLine("行數(shù)=" + rowCount);
        //按照行數(shù)初始化strs元素?cái)?shù)量
        strs = new string[rowCount];
        int colCount = worksheet.GetRow(0).LastCellNum;
        Console.WriteLine("列數(shù)=" + colCount);

        for (int i = 0; i < rowCount; i++)
        {
            Console.Write("第" + i + "行=\n");
            IRow row = worksheet.GetRow(i);
            string rowString = "";
            for (int j = 0; j < colCount; j++)
            {
                string cellValue = $"{row.GetCell(j)}";
                rowString += cellValue + "\t";
            }
            //獲取返回值
            strs[i] = (rowString);
            Console.WriteLine(rowString);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("ReadExcelFile異常:" + ex.Message);
        MessageBox.Show(ex.Message);
    }
    return strs;
}

(2) 讀取EXCEL表格所有數(shù)據(jù)到字符串?dāng)?shù)組

  • 同上面的方法大統(tǒng)小異,不同的是增加了部分限制條件,一方面,既定義了獲取文件行列數(shù)的限制,也規(guī)定了只獲取表中指定列的內(nèi)容,適合在大表格中獲取部分需要的數(shù)據(jù)。另一方面,我們固定獲取指定位置的數(shù)據(jù),轉(zhuǎn)到數(shù)據(jù)結(jié)構(gòu),需要用戶提供的數(shù)據(jù)列標(biāo)題和內(nèi)容必須嚴(yán)格對應(yīng),不然就會(huì)獲取錯(cuò)誤。
struct NEED_AGING_STRUCT
{
		public string MacAddress;
		public string AgingResult;
		public string AgingTime;
}
/// <summary>
/// 讀取EXCEL表格所有需要的數(shù)據(jù)到指定的結(jié)構(gòu)體數(shù)組
/// </summary>
/// <param name="filePath">文件路徑</param>
/// <param name="needAging">獲取結(jié)構(gòu)體數(shù)組</param>
/// <returns></returns>
public int ReadExcelneedToStructs(string filePath, ref NEED_AGING_STRUCT[] needAging)
{
    if (string.IsNullOrEmpty(filePath))
    {
        //無文件路徑
        return 1;
    }

    try
    {
        //創(chuàng)建Excel文件數(shù)據(jù)流對象
        FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
        //創(chuàng)建Excel文件對象
        IWorkbook workbook = new XSSFWorkbook(fileStream);
        //獲取第1個(gè)表單
        ISheet worksheet = workbook.GetSheetAt(0);

        //獲取單元格值行
        int rowCount = worksheet.LastRowNum + 1;
        Console.WriteLine("行數(shù)=" + rowCount);
        if (rowCount <= 1)
        {
            return 2;//小于兩行,無數(shù)據(jù)內(nèi)容
        }

        //按照行數(shù)初始化NEED_AGING_STRUCT元素?cái)?shù)量
        needAging = new NEED_AGING_STRUCT[rowCount - 1];

        //獲取單元格值列
        int colCount = worksheet.GetRow(0).LastCellNum;
        Console.WriteLine("列數(shù)=" + colCount);
        if (colCount != 44)
        {
            return 3;//列數(shù)不正確
        }

        for (int i = 0; i < rowCount; i++)//行循環(huán)
        {
            Console.Write("第" + i + "行=\n");
            IRow row = worksheet.GetRow(i);
            string rowString = "";
            for (int j = 0; j < colCount; j++)//列循環(huán)
            {
                string cellValue = $"{row.GetCell(j)}";
                rowString += cellValue + "\t";
                if (i > 0)//非第一行時(shí)截取數(shù)據(jù)
                {
                    switch (j)
                    {
                        case 4:
                            needAging[i - 1].MacAddress = cellValue;
                            break;
                        case 6:
                            needAging[i - 1].AgingResult = cellValue;
                            break;
                        case 43:
                            needAging[i - 1].AgingTime = cellValue;
                            break;

                        default:
                            break;
                    }
                }
            }

            if (i == 0)
            {
                if (!rowString.Contains("MAC地址") || !rowString.Contains("老化結(jié)束") || !rowString.Contains("老化完成時(shí)間"))
                {
                    return 4;//表格首行格式不正確
                }
            }

            Console.WriteLine(rowString);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("ReadExcelFile異常:" + ex.Message);
        MessageBox.Show(ex.Message);
    }
    return 0;
}

(3) 讀取EXCEL表格所有需要的數(shù)據(jù)到列表

  • 第三種方法就是一種靈活的方式,通過輸入?yún)?shù)來指定或不指定列,最后存到列表list中。
  • 建議用戶可以在提前檢索首行所需要的列,再調(diào)用該數(shù),就可以通用不同格式的Excel表格了。
/// <summary>
/// 讀取EXCEL表格所有需要的數(shù)據(jù)到列表
/// </summary>
/// <param name="filePath">路徑</param>
/// <param name="colCount">指定列數(shù),小于1則不指定</param>
/// <param name="needColumn">需要的列號(hào),null為不指定</param>
/// <param name="getList">輸出list字符串列表</param>
/// <returns>返回空為正常,其它異常</returns>
public string ReadExcelneedToStringList(string filePath, int colCount, int[] needColumn, bool needFirstRow, out List<string> getList)
{
   getList = new List<string> { };
   if (string.IsNullOrEmpty(filePath))
   {
       return "無文件路徑";
   }

   try
   {
       //創(chuàng)建Excel文件數(shù)據(jù)流對象
       FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
       //創(chuàng)建Excel文件對象
       IWorkbook workbook = new XSSFWorkbook(fileStream);
       //獲取第1個(gè)表單
       ISheet worksheet = workbook.GetSheetAt(0);

       //獲取單元格值行
       int rowCount = worksheet.LastRowNum + 1;
       Console.WriteLine($"行數(shù)={rowCount}");
       if (rowCount <= 1)
       {
           return "小于兩行,無數(shù)據(jù)內(nèi)容";
       }
       //獲取單元格值列,colCount大于等于1,才檢查列數(shù),否則不檢查

       int getColumnCount = worksheet.GetRow(0).LastCellNum;
       Console.WriteLine($"讀取列數(shù)/確認(rèn)列數(shù)={getColumnCount}/{colCount}");
       if (colCount >= 1)
       {
           if (getColumnCount != colCount)
           {
               return "列數(shù)不正確";
           }
       }
       int firstRowNum = 0;
       for (int i = 0; i < rowCount; i++)//行循環(huán)
       {
           Console.Write("第" + i + "行=\n");
           IRow row = worksheet.GetRow(i);
           string rowString = "", needRowString = "";
           
           //是否需要獲取第一行標(biāo)題行
           if (needFirstRow) 
               firstRowNum = 0;

           for (int j = 0; j < getColumnCount; j++)//列循環(huán)
           {
               string cellValue = $"{row.GetCell(j)}";
               rowString += cellValue + "\t";
               if (i >= firstRowNum)
               {
                   if (needColumn == null || needColumn.Length == 0)
                   {
                       needRowString += cellValue + "\t";
                   }
                   else
                   {
                       foreach (var item in needColumn)
                       {
                           //獲取需要的列
                           if (j == item)
                           {
                               needRowString += cellValue + "\t";
                               break;
                           }
                       }
                   }
               }
           }
           Console.WriteLine(rowString);

           /*   //可以增加第一列判斷
           if (i == 0)
           {
               if (!rowString.Contains("IP"))
               {
                   return "表格首行格式不正確";//
               }
           }*/
           if (!string.IsNullOrEmpty(needRowString))
           {
               getList.Add(needRowString);
           }
       }
   }
   catch (Exception ex)
   {
       string err = "ReadExcelFile異常:" + ex.Message;
       return err;
   }
   return "success";
}


3、寫Excel表功能函數(shù)設(shè)計(jì)

寫Excel表,即通過已有數(shù)據(jù)導(dǎo)出Excel表,這里講2個(gè)例子。

(1)從DataGridView 導(dǎo)出新的EXCEL

  • 顧名思義,創(chuàng)建新的Excel,需要之前沒有文件,是新創(chuàng)建的,所以在fileName定義時(shí),建議添加時(shí)間信息尾綴,當(dāng)然這里也添加了對文件是否存在的檢查,大文件盡量使用xlsx。
  • 字段名稱field_names可以默認(rèn)也可以自己定義,因?yàn)橛袝r(shí)候需要使用不同的字段名來展示或者輸出給使用者查看,比如輸出為英文標(biāo)題。
  • 這里錯(cuò)誤信息也提供了英中雙語言。
  • 格式字體等細(xì)節(jié),大家可以依據(jù)自己的喜好自行調(diào)整選擇,但是建議使用大家都有的字體格式,避免不同系統(tǒng)用戶出現(xiàn)顯示異常。
/// <summary>
///  NPOI DataGridView 導(dǎo)出新的EXCEL (最大行數(shù)要減去1行做標(biāo)題)
///  03版Excel-xls最大行數(shù)是65535行,最大列數(shù)是256列
///  07版Excel-xlsx最大行數(shù)是1048575行,最大列數(shù)是16384列
/// </summary>
/// <param name="fileName">保存文件名</param>
/// <param name="dataGridView">DataGridView控件</param>
/// <param name="field_names">字段名稱--為空則使用表格的默認(rèn)字段</param>
/// <param name="err_msg">錯(cuò)誤消息</param>
/// <param name="msg_in_english">錯(cuò)誤消息是否用英文</param>
/// <param name="sheetName">表格名稱--有默認(rèn)值</param>
/// <param name="fontname">字體名稱--有默認(rèn)值</param>
/// <param name="fontsize">字體大小--有默認(rèn)值</param>
/// <returns>true或false</returns>
public bool ExportExcel(string fileName, DataGridView dataGridView, string[] field_names, out string err_msg, bool msg_in_english, string sheetName = "Sheet1", string fontname = "Tahoma", short fontsize = 10)
{
    IWorkbook workbook = default;
    ISheet sheet = default;
    Stopwatch sw = null;
    err_msg = "";
    //判斷datagridview中內(nèi)容是否為空
    if (dataGridView.Rows.Count == 0)
    {
        err_msg = msg_in_english ? "The data content is empty!" : "數(shù)據(jù)內(nèi)容為空!";
        return false;
    }

    //檢測文件是否被占用
    if (!IsOccupied(fileName))
    {
        err_msg = msg_in_english ? $"The file {fileName} is occupied。" : $"文件{fileName}被占用。";
        return false;
    }


    //根據(jù)擴(kuò)展名xls和xlsx來創(chuàng)建對象
    string fileExt = Path.GetExtension(fileName).ToLower();
    workbook = null;
    if (fileExt == ".xlsx")
    {
        if (dataGridView.Rows.Count > 1048575 || dataGridView.ColumnCount > 16384)
        {
            err_msg = msg_in_english ? "The number of rows or columns exceeds the specified range" : "DataGridView中行數(shù)或列數(shù)超出范圍(最大行數(shù)是 1048575 行,最大列數(shù)是 16384 列)!";
            return false;
        }
        else
        {
            workbook = new XSSFWorkbook();
        }
    }
    else if (fileExt == ".xls")
    {
        if (dataGridView.Rows.Count > 65535 || dataGridView.ColumnCount > 256)
        {
            err_msg = msg_in_english ? "The number of rows or columns exceeds the specified range" : "DataGridView中行數(shù)或列數(shù)超出范圍(最大行數(shù)是 65535 行,最大列數(shù)是 256 列)!\r\n要導(dǎo)出數(shù)據(jù),請選擇 Excel文件(*.xlsx)";
            return false;
        }
        else
        {
            workbook = new HSSFWorkbook();
        }
    }

    //創(chuàng)建Sheet
    if (workbook != null)
    {
        sheet = workbook.CreateSheet(sheetName);//Sheet的名稱  
    }
    else
    {
        err_msg = msg_in_english ? "Workbook creation failed!" : "workbook創(chuàng)建失敗!";
        return false;
    }

    //程序開始計(jì)時(shí)
    sw = new Stopwatch();
    sw.Start();
    MemoryStream ms = new MemoryStream(); //MemoryStream

    //設(shè)置單元格樣式
    ICellStyle cellStyle = workbook.CreateCellStyle();
    //水平居中對齊和垂直居中對齊
    cellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
    cellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;
    //設(shè)置字體
    IFont font = workbook.CreateFont();
    font.FontName = fontname;//字體名稱
    font.FontHeightInPoints = fontsize;//字號(hào)
    font.Color = NPOI.HSSF.Util.HSSFColor.Black.Index;//字體顏色
    cellStyle.SetFont(font);

    //添加列名
    IRow headRow = sheet.CreateRow(0);
    if (field_names == null || field_names.Length == 0)
    {
        //默認(rèn)使用標(biāo)題
        for (int i = 0; i < dataGridView.Columns.Count; i++)
        {
            //隱藏行列不導(dǎo)出
            if (dataGridView.Columns[i].Visible == true)
            {
                headRow.CreateCell(i).SetCellValue(dataGridView.Columns[i].HeaderText);
                headRow.GetCell(i).CellStyle = cellStyle;
            }
        }
    }
    else
    {
        //自定義標(biāo)題
        for (int i = 0; i < field_names.Length; i++)
        {
            headRow.CreateCell(i).SetCellValue(field_names[i]);
            headRow.GetCell(i).CellStyle = cellStyle;
        }
    }

    //根據(jù)類型寫入內(nèi)容
    for (int rowNum = 0; rowNum < dataGridView.Rows.Count; rowNum++)
    {
        ///跳過第一行,第一行為列標(biāo)題
        IRow dataRow = sheet.CreateRow(rowNum + 1);
        for (int columnNum = 0; columnNum < dataGridView.Columns.Count; columnNum++)
        {
            int columnWidth = (int)sheet.GetColumnWidth(columnNum) / 256; //列寬

            //隱藏行列不導(dǎo)出
            if (dataGridView.Rows[rowNum].Visible == true && dataGridView.Columns[columnNum].Visible == true)
            {
                //防止行列超出Excel限制
                if (fileExt == ".xls")
                {
                    //03版Excel最大行數(shù)是65535行,最大列數(shù)是256列
                    if (rowNum > 65535)
                    {
                        err_msg = msg_in_english ? "The number of rows in the xls file exceeds the limit set by Excel!" : "xls行數(shù)超過Excel限制!";
                        return false;
                    }
                    if (columnNum > 256)
                    {
                        err_msg = msg_in_english ? "The number of columns in the xls file exceeds the limit set by Excel!" : "xls列數(shù)超過Excel限制!";
                        return false;
                    }
                }
                else if (fileExt == ".xlsx")
                {
                    //07版Excel最大行數(shù)是1048575行,最大列數(shù)是16384列
                    if (rowNum > 1048575)
                    {
                        err_msg = msg_in_english ? "The number of rows in the xlsx file exceeds the limit set by Excel" : "xlsx行數(shù)超過Excel限制!";
                        return false;
                    }
                    if (columnNum > 16384)
                    {
                        err_msg = msg_in_english ? "The number of columns in the xlsx file exceeds the limit set by Excel" : "xlsx列數(shù)超過Excel限制!";
                        return false;
                    }
                }

                ICell cell = dataRow.CreateCell(columnNum);
                if (dataGridView.Rows[rowNum].Cells[columnNum].Value == null)
                {
                    cell.SetCellType(CellType.Blank);
                }
                else
                {
                    cell.SetCellValue(dataGridView.Rows[rowNum].Cells[columnNum].Value.ToString());//所有數(shù)據(jù)直接按文本輸出,簡化操作。
                }

                //設(shè)置列寬
                IRow currentRow;
                if (sheet.GetRow(rowNum) == null)
                {
                    currentRow = sheet.CreateRow(rowNum);
                }
                else
                {
                    currentRow = sheet.GetRow(rowNum);
                }

                if (currentRow.GetCell(columnNum) != null)
                {
                    ICell currentCell = currentRow.GetCell(columnNum);
                    int length = Encoding.Default.GetBytes(currentCell.ToString()).Length;

                    if (columnWidth < length)
                    {
                        columnWidth = length + 10; //設(shè)置列寬數(shù)值
                    }
                }
                sheet.SetColumnWidth(columnNum, columnWidth * 256);

                //單元格樣式
                dataRow.GetCell(columnNum).CellStyle = cellStyle;

                //特定單元格紅色背景設(shè)置為紅色背景
                if (dataGridView.Rows[rowNum].Cells[columnNum].Style.BackColor == Color.Red || dataGridView.Rows[rowNum].Cells[columnNum].Style.BackColor == Color.Green)
                {
                    currentRow = sheet.GetRow(rowNum + 1);
                    ICell currentCell = currentRow.GetCell(columnNum);
                    ICellStyle icellStyle = workbook.CreateCellStyle();
                    //水平居中對齊和垂直居中對齊
                    icellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
                    icellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;
                    //設(shè)置字體
                    font.FontName = fontname;//字體名稱
                    font.FontHeightInPoints = fontsize;//字號(hào)
                    font.Color = NPOI.HSSF.Util.HSSFColor.Black.Index;//字體顏色
                    icellStyle.SetFont(font);
                    //設(shè)置單元格顏色
                    icellStyle.FillPattern = FillPattern.SolidForeground;
                    if (dataGridView.Rows[rowNum].Cells[columnNum].Style.BackColor == Color.Red)
                    {
                        icellStyle.FillForegroundColor = 10;//紅色
                    }
                    if (dataGridView.Rows[rowNum].Cells[columnNum].Style.BackColor == Color.Green)
                    {
                        icellStyle.FillForegroundColor = 50;//綠色
                    }
                    currentCell.CellStyle = icellStyle;//設(shè)置
                }
            }
        }
    }

    //保存為Excel文件                  
    workbook.Write(ms);
    FileStream file = new FileStream(fileName, FileMode.Create);
    workbook.Write(file);
    file.Close();
    workbook = null;
    ms.Close();
    ms.Dispose();
    //程序結(jié)束計(jì)時(shí)//
    sw.Stop();
    double totalTime = sw.ElapsedMilliseconds / 1000.0;

    err_msg = msg_in_english ? $"{fileName} export successful,spend {totalTime}s。" : $"{fileName}導(dǎo)出成功,耗時(shí){totalTime}秒。";
    return true;

}

(2)將DataGridView導(dǎo)出添加到EXCEL

  • 這個(gè)例子和上面本質(zhì)上是有著異曲同工之妙, 不同的是如果文件存在則是在原文件尾繼續(xù)添加數(shù)據(jù),特別適合匯總的Excel表文件。
  • 當(dāng)然新文件可以添加,但新文件需要首行標(biāo)題的話需要提前添加,可以結(jié)合前一個(gè)接口程序。
/// <summary>
/// 將DataGridView導(dǎo)出添加到EXCEL(NPOI)
/// </summary>
/// <param name="fileName">保存的文件名</param>
/// <param name="dataGridView">DataGridView數(shù)據(jù)控件</param>
/// <param name="err_msg">錯(cuò)誤消息</param>
/// <param name="msg_in_english">錯(cuò)誤消息是否用英文</param>
/// <param name="sheetName">表格名稱--有默認(rèn)值</param>
/// <param name="fontname">字體名稱--有默認(rèn)值</param>
/// <param name="fontsize">字體大小--有默認(rèn)值</param> 
/// <returns>true或false</returns>
public bool ExportAddToExcel(string fileName, DataGridView dataGridView, out string err_msg, bool msg_in_english, string sheetName = "Sheet1", string fontname = "Tahoma", short fontsize = 12)
{
    err_msg = string.Empty;
    //檢測文件是否被占用
    if (!IsOccupied(fileName))
    {
        err_msg = msg_in_english ? $"The file {fileName} is occupied。" : $"文件{fileName}被占用。";
        return false;
    }

    //獲取擴(kuò)展名xls和xlsx 
    string fileExt = Path.GetExtension(fileName).ToLower();

    // 打開現(xiàn)有的Excel文件,讀取文件流
    FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);
    IWorkbook workbook = new XSSFWorkbook(file);
    ISheet sheet;

    if (string.IsNullOrEmpty(sheetName))
        sheet = workbook.GetSheetAt(0); //使用workbook.GetSheetAt(0)獲取第一個(gè)工作表
    else
        sheet = workbook.GetSheet(sheetName); //指定工作表

    // 檢查sheet是否為空,如果不存在則創(chuàng)建新的sheet
    if (sheet == null)
    {
        sheet = workbook.CreateSheet(sheetName);
    }
    MemoryStream ms = new MemoryStream(); //MemoryStream
    // 創(chuàng)建單元格樣式
    NPOI.SS.UserModel.ICellStyle cellStyle = workbook.CreateCellStyle();
    cellStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.None;
    cellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.None;
    cellStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.None;
    cellStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.None;
    cellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Center;
    cellStyle.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.Center;
    //設(shè)置字體
    IFont font = workbook.CreateFont();
    font.FontName = fontname;//字體名稱
    font.FontHeightInPoints = fontsize;//字號(hào)
    font.Color = NPOI.HSSF.Util.HSSFColor.Black.Index;//字體顏色
    cellStyle.SetFont(font);
    
    int last_row_num = sheet.LastRowNum; // 獲取尾行的行號(hào)
    //根據(jù)類型寫入內(nèi)容
    for (int rowNum = 0; rowNum < dataGridView.Rows.Count; rowNum++)
    {
        IRow row = sheet.CreateRow(++last_row_num);  // 創(chuàng)建新行,行號(hào)+1
        for (int columnNum = 0; columnNum < dataGridView.Columns.Count; columnNum++)
        {
            //隱藏行列不導(dǎo)出
            if (dataGridView.Rows[rowNum].Visible == true && dataGridView.Columns[columnNum].Visible == true)
            {
                //防止行列超出Excel限制
                if (fileExt == ".xls")
                {
                    //03版Excel最大行數(shù)是65535行,最大列數(shù)是256列
                    if (rowNum > 65535)
                    {
                        err_msg = msg_in_english ? "The number of rows in the xls file exceeds the limit set by Excel!" : "xls行數(shù)超過Excel限制!";
                        return false;
                    }
                    if (columnNum > 256)
                    {
                        err_msg = msg_in_english ? "The number of columns in the xls file exceeds the limit set by Excel!" : "xls列數(shù)超過Excel限制!";
                        return false;
                    }
                }
                else if (fileExt == ".xlsx")
                {
                    //07版Excel最大行數(shù)是1048575行,最大列數(shù)是16384列
                    if (rowNum > 1048575)
                    {
                        err_msg = msg_in_english ? "The number of rows in the xlsx file exceeds the limit set by Excel" : "xlsx行數(shù)超過Excel限制!";
                        return false;
                    }
                    if (columnNum > 16384)
                    {
                        err_msg = msg_in_english ? "The number of columns in the xlsx file exceeds the limit set by Excel" : "xlsx列數(shù)超過Excel限制!";
                        return false;
                    }
                }

                //寫入數(shù)據(jù)
                //row.CreateCell(0).SetCellValue(2); //row.CreateCell(1).SetCellValue("Charlie"); 
                if (dataGridView.Rows[rowNum].Cells[columnNum].Value == null)
                {
                    row.CreateCell(columnNum).SetCellType(CellType.Blank);
                }
                else
                {
                    row.CreateCell(columnNum).SetCellValue(dataGridView.Rows[rowNum].Cells[columnNum].Value.ToString());//所有數(shù)據(jù)直接按文本輸出
                }
                //單元格樣式
                row.GetCell(columnNum).CellStyle = cellStyle;

            }
        }
    }

    // 保存更改
    using (FileStream fileOut = new FileStream(fileName, FileMode.Open, FileAccess.Write))
    {
        workbook.Write(fileOut);
    }
    ms.Close();
    ms.Dispose();
    workbook.Close();

    // workbook資源釋放
    file.Close();
    return true;
}

(3)引用系統(tǒng)API檢測文件是否被占用

  • 在保存文件的時(shí)候經(jīng)常需要用到
 #region 檢測文件是否被占用 
 // 判斷文件是否打開
 [DllImport("kernel32.dll")]
 public static extern IntPtr _lopen(string lpPathName, int iReadWrite);

 // 關(guān)閉文件句柄
 [DllImport("kernel32.dll")]
 public static extern bool CloseHandle(IntPtr hObject);

 // 常量
 public const int OF_READWRITE = 2;
 public const int OF_SHARE_DENY_NONE = 0x40;
 public static readonly IntPtr HFILE_ERROR = new IntPtr(-1);

 private bool IsOccupied(string filePath)
 {       

     if (!File.Exists(filePath))
     {
         //文件不存在
         return true;
     }
     IntPtr vHandle = _lopen(filePath, OF_READWRITE | OF_SHARE_DENY_NONE);
     if (vHandle == HFILE_ERROR)
     {
         //文件被占用
         return false;
     }
     //文件沒被占用
     CloseHandle(vHandle);
     return true;
 }
#endregion //檢測文件是否被占用 

總結(jié)

本文通過NPIO接口C#語言描述了3個(gè)Excel導(dǎo)入的函數(shù)和2個(gè)導(dǎo)出的行數(shù),各有千秋,大同小異。朋友們可以自己研究,看看有沒有比NPOI更加好的方案來控制Excel的讀寫,可以告訴我。

以上就是C#通過NPIO讀寫Excel表的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于C# NPIO讀寫Excel表的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#實(shí)現(xiàn)xml文件的讀取與寫入簡單實(shí)例

    C#實(shí)現(xiàn)xml文件的讀取與寫入簡單實(shí)例

    這篇文章主要介紹了C#實(shí)現(xiàn)xml文件的讀取與寫入方法,涉及C#操作XML文件的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08
  • 在C#中捕獲內(nèi)存不足異常

    在C#中捕獲內(nèi)存不足異常

    這篇文章主要介紹了在C#中捕獲內(nèi)存不足異常,下面文章內(nèi)容圍繞如何在C#中捕獲內(nèi)存不足異常的相關(guān)資料展開詳細(xì)內(nèi)容,具有一定的參考價(jià)值,需要的小伙伴可以參考一下,希望對你有所幫助
    2021-12-12
  • 詳解C#如何讀寫config配置文件

    詳解C#如何讀寫config配置文件

    這篇文章主要介紹了詳解C#如何讀寫config配置文件,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12
  • C#高效解析并提取PDF文檔中的文本與表格實(shí)戰(zhàn)指南

    C#高效解析并提取PDF文檔中的文本與表格實(shí)戰(zhàn)指南

    PDF文檔作為一種通用、安全且跨平臺(tái)的文檔格式,已成為現(xiàn)代業(yè)務(wù)流程中不可或缺的一部分,本文將深入探討如何利用C#結(jié)合高效的PDF處理庫,實(shí)現(xiàn)PDF文檔的自動(dòng)化解析,從基礎(chǔ)的環(huán)境配置到復(fù)雜的表格數(shù)據(jù)提取,為您提供一套全面的實(shí)踐指南
    2025-12-12
  • vs2019安裝和使用詳細(xì)圖文教程

    vs2019安裝和使用詳細(xì)圖文教程

    這篇文章主要介紹了vs2019安裝和使用詳細(xì)圖文教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 使用C#和WinForms創(chuàng)建動(dòng)態(tài)圖表的兩種方法

    使用C#和WinForms創(chuàng)建動(dòng)態(tài)圖表的兩種方法

    本文詳細(xì)介紹了如何使用C#和WinForms中的Chart控件創(chuàng)建動(dòng)態(tài)圖表,包括實(shí)例化圖表、添加數(shù)據(jù)點(diǎn)、使用多線程實(shí)現(xiàn)實(shí)時(shí)更新,并提供兩種方法創(chuàng)建圖表實(shí)例,需要的朋友可以參考下
    2025-09-09
  • c# Newtonsoft 六個(gè)值得使用的特性(下)

    c# Newtonsoft 六個(gè)值得使用的特性(下)

    這篇文章主要介紹了c# Newtonsoft 六個(gè)值得使用的特性,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • C#簡單的特殊輸出實(shí)例

    C#簡單的特殊輸出實(shí)例

    這篇文章主要介紹了C#簡單的特殊輸出,以實(shí)例實(shí)現(xiàn)了針對一些特殊字符與位置的輸出控制,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-11-11
  • C#實(shí)現(xiàn)順序表(線性表)完整實(shí)例

    C#實(shí)現(xiàn)順序表(線性表)完整實(shí)例

    這篇文章主要介紹了C#實(shí)現(xiàn)順序表(線性表)的方法,結(jié)合完整實(shí)例形式分析了順序表的原理及C#相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2016-06-06
  • C#使用NPOI操作Excel工具類的實(shí)現(xiàn)

    C#使用NPOI操作Excel工具類的實(shí)現(xiàn)

    NPOI是POI項(xiàng)目的.NET遷移版本,使用NPOI可以在沒有安裝Office或者相應(yīng)環(huán)境的機(jī)器上對Word或Excel文檔進(jìn)行讀寫操作,下面我們就來學(xué)習(xí)一下如何使用NPOI編寫操作Excel的工具類吧
    2023-11-11

最新評(píng)論

武夷山市| 遵化市| 浦城县| 蓬莱市| 中宁县| 巢湖市| 陆良县| 奇台县| 英超| 云安县| 龙陵县| 庆城县| 赣榆县| 乐东| 寿阳县| 本溪| 新营市| 苗栗县| 中宁县| 双流县| 邵阳县| 凤城市| 鹤峰县| 浏阳市| 通化市| 杭州市| 西城区| 子长县| 咸丰县| 景洪市| 郸城县| 高邮市| 柳州市| 沙湾县| 牙克石市| 图片| 北票市| 政和县| 枝江市| 神池县| 含山县|